Skip to content

Latest commit

 

History

History
1698 lines (1097 loc) · 75.7 KB

PRG-0004-A-Game-Development-Blackboard-Part-1.md

File metadata and controls

1698 lines (1097 loc) · 75.7 KB

Game Development Blackboard - Part 1

2019-09-26 星期四

C# List 自定义排序

list.Sort(
    delegate(Node n1, Node n2)
    {
        return n1.ID.CompareTo(n2.ID);
    }
);

Unity 富文本 log

Debug.Log("<color=darkgreen>这是深绿色的日志</color>");

2019-09-23 星期一

Unity 2017 Game Optimization

Unity Tips

PlayerPrefs location

On macOS PlayerPrefs are stored in ~/Library/Preferences folder, in a file named unity.[company name].[product name].plist, where company and product names are the names set up in Project Settings. The same .plist file is used for both Projects run in the Editor and standalone players. On Windows, PlayerPrefs are stored in the registry under HKCU\Software[company name][product name] key, where company and product names are the names set up in Project Settings. On Linux, PlayerPrefs can be found in ~/.config/unity3d/[CompanyName]/[ProductName] again using the company and product names specified in the Project Settings. On Windows Store Apps, Player Prefs can be found in %userprofile%\AppData\Local\Packages[ProductPackageId]>\LocalState\playerprefs.dat On Windows Phone 8, Player Prefs can be found in application's local folder, See Also: Directory.localFolder On Android data is stored (persisted) on the device. The data is saved in SharedPreferences. C#/JavaScript, Android Java and Native code can all access the PlayerPrefs data. The PlayerPrefs data is physically stored in /data/data/pkg-name/shared_prefs/pkg-name.xml. On WebGL, PlayerPrefs are stored using the browser's IndexedDB API. On iOS, PlayerPrefs are stored in /Library/Preferences/[bundle identifier].plist.

2019-09-11 星期三

XML 格式设计

2019-09-09 星期一

FairyGUI

PureMVC

在 PureMVC 实现的经典 MVC 元设计模式中,Model、View 和 Controller 分别由一个单例类来管理,合称为核心层或核心角色。另外,在 PureMVC 中还提供了一个单例类——Fasade,主要作用是作为与核心层通信的唯一接口,简化开发复杂度。

除了这几个主要对象以外,框架中还有 Proxy、Mediator 和 Command,它们的作用是:

  • Proxy 对象负责操作数据模型,与远程服务通信存取数据,这样可以保证 Model 层的可移植性。通常 Proxy 对象的引用保存在 Model 中。
  • View 保存对 Mediator 对象的引用。由 Mediator 对象来操作具体的视图组件(View Component),它的作用还包括:添加事件监听器,发送或接收 Notification,直接改变视图组件的状态。通过这样,就可以把视图和控制它的逻辑分离开来。
  • Command 对象是无状态的,只在需要时才被创建。Command 可以获取 Proxy 对象并与之交互,发送 Notification,执行其他的 Command。经常用于复杂的或系统范围的操作,如应用程序的「启动」与「关闭」。应用程序的业务逻辑应该在这里实现。

除了基本的对象结构以外,为了解耦合,PureMVC 框架中引入了事件机制,这是个非常简单的观察者设计模式,所有的事件都是一个 Notification,不同对象之间通过 Notification 来同步操作和交换信息。例如如果想更新界面中某个 Mediator,首先我们定义 Notification 用于此目的,然后注册 Mediator 监听该 Notification,然后就可以在程序中任何地方生成一个 Notification,通过事件机制,Mediator 就会接收到 Notification,然后更新需要的部分。整个过程 Mediator 只和 Notification 有关,没有其他依赖,有效地降低了对象之间的依赖程度。�

抽象物品

抽象物品用于指代游戏系统中任意可以附加于玩家的东西,比如金币、宝石、经验、道具、英雄、宠物、装备、积分、体力等等,都可以用通用抽象物品接口来替代。 为什么做抽象?

  • 解耦各个模块�
  • 配表更灵活
  • 方便交换数据

从零开始制作 SLG 游戏

2019-09-03 星期二

手动开启/关闭 GC

ILRuntime

  1. 基本限制 热更部分的代码都不继承MonoBehaviour,也就是都不挂脚本,非热更部分随意:热更对MonoBehaviour这种比较特殊东西的支持都挺麻烦,要么不用,要么只是做个不可热更的消息转发层;要么开发时挂脚本,打包时用某种特殊的方式把它变成代码里动态AddComponent。
  2. Android 不用任何第三方的热更方案,用C#反射执行DLL,性能和代码写法和纯C#基本一样。 Google Pay强制要求在2019年8月之前App都支持64位,Unity的应对方案是Android IL2cpp,暂时没有支持mono backend 64位的打算。所以到时候只能是IL2CPP + ILRuntime的方式,性能会差一大截,主要慢在ILRuntime上。
  3. iOS ILRuntime + DLL 解释执行,当然是在IL2CPP下。
  4. 优点 语言(C#)\开发环境\工具链统一,随时可以变成不支持热更形式,如果苹果未来不允许任何解释执行的方式。 框架搭好后,满足一些限制条件(非硬性限制,主要是避免麻烦,限制主要是1个,可热更部分的代码不要继承不可热更的代码, 不继承MonoBehaviour是这个限制的子集),写逻辑的同学开发方式和原生C#开发完全一样,包括调试。 第三方插件直接可用(大部分插件都是基于C#写的).
  5. 缺点 稳定性的坑还是有一些:通常发生于一些相对高级的语言特性组合,特别是各种反射代码。另外.net4.6的async\wait所支持的现在版本应该也还不够稳定,纯计算的性能弱于Lua,计算密集型的代码还是想办法放在不可热更新的部分吧。 历史短,Git贡献者少,项目考验少(据我的了解,上线的商业项目在x - 1x之间,具体的项目有MMO,SLG,休闲,也有棋牌),原理上大的优化空间没有,小的优化空间还是有一些;另外整合了各种常用Feature的框架也少 。

基于 ILRuntime 的完整 C# 热更方案

2019-08-28 星期三

C# 与 Lua 数据共享

Sublime Text 的 Protobuf 语法高亮插件

使用方法:

  • Preferences -> Browse Packages...
  • 打开 C:\Users\Administrator\AppData\Roaming\Sublime Text 3\Packages 目录,将下载好的插件文件放置在 Protobuf 目录下
  • 重启 Sublime Text 3
  • 打开 .proto 文件,选择 Protocol Buffer 格式,即可看到语法已高亮显示

英文缩写查询网站

使用方法:

  • 点选 Term >> Abbreviation
  • 在搜索框输入要查询的英文单词,点击 SEARCH

2019-08-24 星期六

EmmyLua 插件

TSV 使用

Unreal 4 Engine Docs

2019-08-17 星期六

.NET 4.x

2019-08-12 星期一

Unity Gameplay 工具集

  • 实体组件(Entity-Component)
  • 节点可视化编程(Node-based Visual Scripting)
- 状态机(Finite State Machine)
- 行为树(Behavior Tree)
- 事件驱动可视化编程(Event Driven Visual Scripting)
- 非线性编辑(Non-linear editing)

Unity 项目性能优化

Unity 的 GPU 内存机制

程序化生成算法

2019-08-02 星期五

Unity ECS

An Entity Component System (ECS) architecture separates identity (entities), data (components), and behaviour (systems). The architecture focuses on the data. Systems transform the data from an input state to an output state by reading streams of component data, which are indexed by entities.

组合式 Entity 的架构设计

  • 将实体分为属性部分(Property)和行为部分(Behavior)
  • 行为部分用组件(Component)来实现
  • 属性部分分为固有属性(Built-in Property)和自定义属性(User-defined Property),固有属性用成员变量来实现,自定义属性用 key-value 对来实现,可以通过继承来扩展固有属性
  • 可以用数据驱动的方式来配置属性和组件
  • 实体和组件的通信靠属性作为共享数据
  • 组件和组件的通信靠消息,不暴露组件的内部变量
  • 实体和实体的通信靠消息
  • 使用层次化(引擎层和游戏层)的方式来设计实体和组件

Entity Component System

Entitas

Entitas is a super fast and lightweight C# Entity-Component-System (ECS) framework, specifically designed for use with the Unity engine. Internal caching and blazing fast component access makes it second to none. It's also been carefully designed to work optimally in a garbage collected environment.

AI 行为树的设计与实现(lua)

AOI 同步方案

  • 空间切割网格算法
  • 十字链表算法
  • 分层 AOI

UI 半自动化开发方案

MMORPG 技能系统

技能模块每个部分的职责和原理:

  • 技能信息管理:管理unit所拥有的技能以及技能的等级、cd等。在我们游戏中,这里还需要负责管理符文,符文会对技能信息进行修改。
  • 技能调用接口:AI或者UI操作触发技能,触发技能时可能选择了一个目标(AI),也可能并没有目标。
  • 技能流程管理:一个技能可能由多个子技能以移动的执行模式组合而成,而每一个最终执行的技能执行过程也存在一个流程,一般包括:前摇过程-结算点-后摇过程。技能在前摇结束时进入技能真正的结算流程,结算流程可能创建子弹,也可能触发buf或者创建法术场。
  • 技能目标查找:若技能触发时已经设置了技能目标unit(如怪物AI释放技能),则直接将其作为目标unit,否则需要根据一定的策略选择一个目标。此外,技能释放的时候还需要释放方向和释放位置等信息,也通过这个模块获取。
  • 技能表现:技能释放过程中,需要创建相应的特效以及执行相应的动作。
  • 技能创生体(buf/弹道/法术场)管理:buf挂在unit身上,可能影响unit的一些行为和状态;法术场一般由场景管理,影响场景中某范围内的unit;弹道就是技能创建的一个子弹,这个子弹可能以不同的路线移动(直线/抛物线/直接命中等)

游戏数值系统

(评论更精彩)

2019-07-24 星期三

C# 的类和结构

  • 类是引用类型。 创建类的对象后,向其分配对象的变量仅保留对相应内存的引用。 将对象引用分配给新变量后,新变量会引用原始对象。 通过一个变量所做的更改将反映在另一个变量中,因为它们引用相同的数据。
  • 结构是值类型。 创建结构时,向其分配结构的变量保留结构的实际数据。 将结构分配给新变量时,会复制结构。 因此,新变量和原始变量包含相同数据的副本(共两个)。 对一个副本所做的更改不会影响另一个副本。
  • 一般来说,类用于对更复杂的行为或应在类对象创建后进行修改的数据建模。 结构最适用于所含大部分数据不得在结构创建后进行修改的小型数据结构。

struct 特性:

结构在以下方面比类的限制更多:

  • 在结构声明中,除非将字段声明为 const 或 static,否则无法初始化。
  • 结构不能声明无参数构造函数(没有参数的构造函数)或终结器。
  • 结构在分配时进行复制。 将结构分配给新变量时,将复制所有数据,并且对新副本所做的任何修改不会更改原始副本的数据。 在处理值类型的集合(如 Dictionary<string, myStruct>)时,请务必记住这一点。
  • 结构是值类型,不同于类,类是引用类型。
  • 与类不同,无需使用 new 运算符即可对结构进行实例化。
  • 结构可以声明具有参数的构造函数。
  • 一个结构无法继承自另一个结构或类,并且它不能为类的基类。 所有结构都直接继承自 ValueType,后者继承自 Object。
  • 结构可以实现接口。
  • 结构不能为 null,并且不能向结构变量分配 null,除非将变量声明为可为 null 的类型。

2019-07-21 星期日

C# 边遍历边删除 List 元素

for(int i = list.Count - 1; i >= 0; i--)
{
    if(condition)
    {
        list.RemoveAt(i);
        break;
    }
}

2019-07-10 星期三

Unity 知识点

2019-06-26 星期三

Live 2D

2019-06-22 星期六

Unity 项目资源提取工具

  1. disunity
  2. UnityAssetExplorer
  3. AssetStudio

2019-06-18 星期二

反 Hook

2019-06-13 星期四

iPhone 屏幕分辨率

神经网络

2019-06-02 星期日

抽象类与接口

1.abstract class 在 c# 语言中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个 interface。 2.在 abstract class 中可以有自己的数据成员,也可以有非 abstarct 的成员方法,而在 interface 中,只能够有静态的不能被修改的数据成员(也就是必须是 static final 的,不过在 interface 中一般不定义数据成员),所有的成员方法都是 abstract 的。 3.abstract class 和interface 所反映出的设计理念不同。abstract class 表示的是 "is-a" 关系,interface 表示的是 "like-a" 关系。 4.实现抽象类和接口的类必须实现其中的所有方法。抽象类中可以有非抽象方法。接口中则不能有实现方法。 5.接口中定义的变量默认是 public static final 型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值。 6.抽象类中的变量默认是 friendly 型,其值可以在子类中重新定义,也可以重新赋值。 7.接口中的方法默认都是 public abstract 类型的。

AssetBundle

2019-05-21 星期二

UML

Unity 资源引用丢失导致 Crash

优秀开发经验

2019-05-19 星期日

核心游戏系统架构

行为树与游戏 AI

行为树的核心思想有三个方面:

  • 逻辑分离
  • 逻辑关联
  • 逻辑抽象

AI 中的参数系统

对于一个新的参数系统,我希望它能有如下的特性:

  • 仅支持静态的参数:对于游戏来说是只读的,也就是游戏在运行时不允许修改这些参数,但可以通过外部工具进行调试
  • 支持文档化
  • 支持实时的修改:不需要重新启动游戏
  • 支持序列化到文件:可以将调整好的参数存成文件,以便下一次启动游戏时生效
  • 支持逻辑关联
  • 支持自动的合法性检查
  • 高效和便捷的定义和调用

游戏服务器架构

协议的选择 总体来说,COC、KOA (阿瓦隆之王)等地图类少交互的游戏用 TCP 是没有问题的,而 CR(皇室战争)、自由之战、全民枪战、枪林弹雨,这类 MOBA、FPS 等强联网需求的对战游戏,UDP 基本是必备的。 同步机制 帧同步: 快节奏、同时希望降低服务器不必要负载的对战类手游,帧同步是不二的选择。帧同步的好处是可以精减上传信息,只是做一些简单的数据汇总上报,需要的带宽非常少。 状态同步: 安全性很高,但状态同步需要的带宽量远大于帧同步,而全球服游戏本身面临着非常严峻的全球网络环境,甚至很多情况下需要专线来解决网络问题,这时候,网络开销将是比较大的成本。 简而言之,一句话:如果你想做全球服游戏,请务必学会帧同步。

Excel 转换为 Protobuf 工具

2019-05-13 星期一

Awesome Game Sample

Game Framework

Unity 资源管理机制

Unity AssetBundle 与打包

2019-04-10 星期三

Android Crash 堆栈解读和 so 文件反编译

SEGV_ACCERR 和 SEGV_MAPERR

There are two common kinds of SEGV, which is an error that results from an invalid memory access:

  1. A page was accessed which had the wrong permissions. E.g., it was read-only but your code tried to write to it. This will be reported as SEGV_ACCERR.
  2. A page was accessed that is not even mapped into the address space of the application at all. This will often result from dereferencing a null pointer or a pointer that was corrupted with a small integer value. This is reported as SEGV_MAPERR.

SEGV_MAPERR means you tried to access an address that doesn't map to anything. SEGV_ACCERR means you tried to access an address that you don't have permission to access.

So in both cases you accessed an address you shouldn't have, which is probably the only thing your actual code is guilty of. In the former case there's no memory in that address range anyway. In the latter case there is memory in that address range but you don't own it.

If you were to access a random address then which you get depends on how the OS happens to have your process set up at that moment.

Java 多线程解压

2019-03-30 星期六

Dictionary 的使用注意

2019-03-20 星期三

获取 iOS Application.persistentDataPath 目录中的文件

  • 在 Unity Build 出来的 Xcode 工程的 info.plist 中添加一行:

    • Key:Application Support iTunes file sharing0
    • Type:Boolean
    • Value: YES

保存文件。Build 出来的 iOS 安装包即可以通过 iTunes 软件导出 Application 的 persistentDataPath 目录下的文件了。

2019-03-16 星期六

iOS 中查看 Unity 程序运行时日志

使用 MonoDevelop 进行断点调试

Xcode Build iOS 包 Tips

I tracked this problem down to the "debug executable" checkbox in the product scheme (product->scheme->edit scheme->info->debug executable checkbox). I unchecked that and this stopped happening (as well as a couple other weird issues - no output in console being one).

2019-02-16 星期六

Time.unscaledTime VS Time.realtimeSinceStartup

unscaledTime:

The timeScale-independant time for this frame (Read Only). This is the time in seconds since the start of the game.

It's the amount of time that has passed since the start of the game at the beginning of this frame.

Where as realTimeSinceStartup:

Note that realtimeSinceStartup returns time as reported by system timer. Depending on the platform and the hardware, it may report the same time even in several consecutive frames. If you're dividing something by time difference, take this into account (time difference may become zero!).

Unity 的文件引用

环形 Buffer 组件

2019-01-24 星期四

Unity Android 包的加密

Android 平台下 Unity 应用 Crash

在 Unity 中使用多线程

2019-01-11 星期五

C# 计算代码运行时间

var watch = System.Diagnostics.Stopwatch.StartNew();
// the code that you want to measure comes here
watch.Stop();
var elapsedMs = watch.ElapsedMilliseconds;

使用 Unity Profiler 调试 Android 包

2018-12-01 星期六

Unity 日志保存位置

Mac OS X

~/Library/Logs/Unity/Editor.log

Windows

C:\Users\username\AppData\Local\Unity\Editor\Editor.log

2018-09-29 星期六

C# 编码约定

2018-09-19 星期三

Unity 物理系统问题

Solution was easy. Simply disable PCM in PhysicsManager!

Enable PCM

Tick this checkbox to enable the persistent contacts manifold (PCM) contacts generation method of the physics engine. This means that fewer contacts are regenerated every physics frame, and more contact data is shared across frames. The PCM contacts generation path is also more accurate, and usually produces better collision feedback in most of the cases. See Nvidia documentation on Persistent Contact Manifold for more information. Note: Before Unity 5.5, Unity used a contacts generation method called SAT, based on the separating axis theorem (see dyn4j.org’s guide to SAT). PCM is more efficient, but for older projects, you might find it easier to continue using SAT, to avoid needing to retweak physics slightly. PCM can result in a slightly different bounce, and fewer useless contacts end up in the contacts buffers (that is, the arrays you get in the Collision instance passed to OnCollisionEnter, OnCollisionStay, OnCollisionExit).

Android Debug Bridge 的使用

常用的 adb 命令:

# 查看已连接的设备列表
adb devices
# 通过 IP 和端口号连接到指定设备
adb connect 127.0.0.1:7555
# 清除所有旧的日志
adb logcat -c
# 将最新的 Unity 日志 dump 到指定文件中
adb logcat -s Unity -d > c:/adblog.txt
# 将日志持续输出到指定文件中
adb logcat -s Unity > c:/adblog.txt

使用 adb 和 Android Studio 查看 Unity Android 包的实时运行日志:

  • 打开 Android 手机的开发者选项,开启 USB 调试,使用数据线将手机连接到调试 PC,将 USB 连接模式设置为传输文件
  • 打开 Android Studio,切换到 Logcat 视窗
  • 打开 Windows 命令行窗口,输入 adb disconnect,再输入 adb connect
  • 此时 Logcat 视窗中应该可选择已连接的设备,并开始打印实时运行日志了

LogViewer 日志查看工具

2018-09-12 星期三

游戏引擎

2018-09-11 星期二

弱网模拟工具 clumsy

C# 中获取毫秒数

2018-08-23 星期四

finally in Java

GC in Java

MonoBehaviour 单例和 DontDestroyOnLoad

Unity 场景加载完毕回调

using UnityEngine.SceneManagement;
void OnEnable()
{
    //Tell our 'OnLevelFinishedLoading' function to start listening for a scene change as soon as this script is enabled.
    SceneManager.sceneLoaded += OnLevelFinishedLoading;
}

void OnDisable()
{
    //Tell our 'OnLevelFinishedLoading' function to stop listening for a scene change as soon as this script is disabled. Remember to always have an unsubscription for every delegate you subscribe to!
    SceneManager.sceneLoaded -= OnLevelFinishedLoading;
}

void OnLevelFinishedLoading(Scene scene, LoadSceneMode mode)
{
    Debug.Log("Level Loaded");
    Debug.Log(scene.name);
    Debug.Log(mode);
}

2018-08-21 星期二

C# Reference Docs

Java 与 C# 的类型

byte:8位,最大存储数据量是255,存放的数据范围是-128~127之间
short:16位,最大数据存储量是65536,数据范围是-32768~32767之间
int:32位,最大数据存储容量是2的32次方减1,数据范围是负的2的31次方到正的2的31次方减1
long:64位,最大数据存储容量是2的64次方减1,数据范围为负的2的63次方到正的2的63次方减1
float:32位,数据范围在3.4e-45~1.4e38,直接赋值时必须在数字后加上f或F
double:64位,数据范围在4.9e-324~1.8e308,赋值时可以加d或D也可以不加
boolean:只有true和false两个取值
char:16位,存储Unicode码,用单引号赋值
有符号的整型
sbyte:8 位,介于 -128 到 127 之间
short:16 位,介于 -32,768 到 32,767 之间
int:32 位,介于 -2,147,483,648 到 2,147,483,647 之间
long:64 位,介于 -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 之间

无符号的整型
byte:8 位,介于 0 到 255 之间
ushort:16 位,介于 0 到 65,535 之间
uint:32 位,介于 0 到 4,294,967,295 之间
ulong:64 位,介于 0 到 18,446,744,073,709,551,615 之间

浮点
float:32 位,介于 1.5 × 10-45 到 3.4 × 1038 之间,7 位精度
double:64 位,介于 5.0 × 10-324 到 1.7 × 10308 之间,15 位精度

十进制
decimal:128 位,至少介于 -7.9 × 10-28 到 7.9 × 1028 之间,至少为 28 位精度

C# 的字节操作工具类 BitConverter

使用 System.BitConverter 在所有基本数值类型和 byte 类型之间相互转换。

C# 中的字节集合工具类 MemoryStream

使用 System.IO.MemoryStream 操作字节数组

将 long 数值装换为十六进制字符串显示

Console.WriteLine(string.Format("{0:X}", 5488461193L));

2018-08-17 星期五

Unity 中定位 C# 脚本中的死循环

2018-07-24 星期二

优化 NGUI 堆内存分配

如何大幅优化 NGUI 的堆内存分配 - 侑虎科技

通用 Java 程序启动脚本

linux 下通用的 Java 程序启动脚本 - 博客园

shell 脚本最后部分有语法错误,需留意!

简化注释版本的 shell 脚本如下:

#!/bin/sh

#############################################
#环境变量及 JVM 参数设置
#############################################

#JDK所在路径
JAVA_HOME=/Users/developer/dev/jdk1.8.0_181

#执行程序使用的系统用户(不推荐使用 root)
RUNNING_USER=root

#Java程序所在路径(classes的上一级目录)
APP_HOME=/Users/developer/dev/jdk1.8.0_181/bin/robot

#需要启动的Java主程序(main方法类)
APP_MAINCLASS=com.tc.performance.Test

#拼接CLASSPATH参数,包括项目引用的所有jar包
CLASSPATH=$APP_HOME/classes
for i in "$APP_HOME"/lib/*.jar; do
    CLASSPATH="$CLASSPATH":"$i"
done

#日志文件路径
LOG_FILE=$APP_HOME/logs/`date +%Y%m%d%H%M%S`.log
touch ${LOG_FILE}

#Java虚拟机启动参数
JAVA_OPTS="-ms128m -mx128m -Xmn64m -Djava.awt.headless=true -XX:MaxPermSize=64m"

#############################################
#(函数)判断程序是否已启动
#############################################

psid=0

checkpid() {
   javaps=`$JAVA_HOME/bin/jps -l | grep $APP_MAINCLASS`
   if [ -n "$javaps" ]; then
      psid=`echo $javaps | awk '{print $1}'`
   else
      psid=0
   fi
}

#############################################
#(函数)启动程序
#############################################

start() {
   checkpid
   if [ $psid -ne 0 ]; then
      echo "================================"
      echo "warn: $APP_MAINCLASS already started! (pid=$psid)"
      echo "================================"
   else
      echo -n "Starting $APP_MAINCLASS ..."
      JAVA_CMD="nohup $JAVA_HOME/bin/java $JAVA_OPTS -classpath $CLASSPATH $APP_MAINCLASS >${LOG_FILE} 2>&1 &"
      su - $RUNNING_USER -c "$JAVA_CMD"
      checkpid
      if [ $psid -ne 0 ]; then
         echo "(pid=$psid) [OK]"
         echo "================================"
         tail -f ${LOG_FILE}
      else
         echo "[Failed]"
      fi
   fi
}

#############################################
#(函数)停止程序
#############################################

stop() {
   checkpid
   if [ $psid -ne 0 ]; then
      echo -n "Stopping $APP_MAINCLASS ...(pid=$psid) "
      su - $RUNNING_USER -c "kill -9 $psid"
      if [ $? -eq 0 ]; then
         echo "[OK]"
      else
         echo "[Failed]"
      fi
      checkpid
      if [ $psid -ne 0 ]; then
         stop
      fi
   else
      echo "================================"
      echo "warn: $APP_MAINCLASS is not running"
      echo "================================"
   fi
}

#############################################
#(函数)检查程序运行状态
#############################################

status() {
   checkpid
   if [ $psid -ne 0 ];  then
      echo "$APP_MAINCLASS is running! (pid=$psid)"
   else
      echo "$APP_MAINCLASS is not running"
   fi
}

#############################################
#(函数)打印系统环境参数
#############################################

info() {
   echo "System Information:"
   echo "****************************"
   echo `head -n 1 /etc/issue`
   echo `uname -a`
   echo
   echo "JAVA_HOME=$JAVA_HOME"
   echo `$JAVA_HOME/bin/java -version`
   echo
   echo "APP_HOME=$APP_HOME"
   echo "APP_MAINCLASS=$APP_MAINCLASS"
   echo "****************************"
}

#############################################
#根据第一个参数执行相应操作
#############################################

case "$1" in
   'start')
      start
      ;;
   'stop')
      stop
      ;;
   'restart')
      stop
      start
      ;;
   'status')
      status
      ;;
   'info')
      info
      ;;
      *)
   echo "Usage: $0 {start|stop|restart|status|info}"
   exit 1
   ;;
esac

2018-06-27 星期三

Java 读写文件

Eclipse 反编译插件

2018-06-14 星期四

查找资源引用

2018-05-23 星期三

将 Quaternion 转换为一个方向向量

A quaternion doesn't have a direction by itself. It is a rotation. It can be used to rotate any vector by the rotation it represents. Just multiply a Vector3 by the quaternion.

Vector3 targetForward = targetRot * Vector3.forward;

C# 代码文档注释

2018-05-19 星期六

持续优化

基于团队的持续优化之道 - 知乎专栏

2018-04-12 星期四

C# 中的 var 关键字

var 可以理解为匿名类型,是一个声明变量的占位符,主要用于在声明变量时,无法确定数据类型时使用。使用 var 关键字需注意:

  • 必须在定义时初始化
  • 一旦初始化完成,就不能再给变量赋予与初始类型不一致的值
  • var 声明的变量必须是局部变量
  • 使用 var 定义变量和 object 不同,它在效率上与使用强类型方式定义变量完全相同

2018-03-19 星期一

获取子对象中组件的引用

includeInactive 参数设置为 true 时,即使该对象为 inactive 也可以获取到其组件的引用

关闭两个 Collider 间的碰撞检测

2018-03-16 星期五

NavMesh 导航网格

测试某一点坐标是否在导航网格中: NavMesh.SamplePosition

获取某一点坐标就近导航网格边缘的坐标: NavMesh.FindClosestEdge

导出NavMesh可行走区域信息 - CSDN

2018-03-07 星期三

腾讯专家答疑

网易游戏技术分享

Unity 框架

寻路算法

行为树

Behavior Tree 行为树

行为树插件

BT-Framework 行为树框架

2018-02-20 星期二

Rigidbody Collision Detection Mode

Collision Detection

Used to prevent fast moving objects from passing through other objects without detecting collisions.

  • Discrete - Use Discreet collision detection against all other colliders in the scene. Other colliders will use Discreet collision detection when testing for collision against it. Used for normal collisions (This is the default value).

  • Continuous - Use Discrete collision detection against dynamic colliders (with a rigidbody) and continuous collision detection against static MeshColliders (without a rigidbody). Rigidbodies set to Continuous Dynamic will use continuous collision detection when testing for collision against this rigidbody. Other rigidbodies will use Discreet Collision detection. Used for objects which the Continuous Dynamic detection needs to collide with. (This has a big impact on physics performance, leave it set to Discrete, if you don’t have issues with collisions of fast objects)

  • Continuous Dynamic - Use continuous collision detection against objects set to Continuous and Continuous Dynamic Collision. It will also use continuous collision detection against static MeshColliders (without a rigidbody). For all other colliders it uses discreet collision detection. Used for fast moving objects.

  • Rigidbody - Unity Manual

  • Collision Detection: Discrete vs. Continuous vs. Continuous Dynamic - Unity Forums

Rigidbody Interpolate

Interpolate

Try one of the options only if you are seeing jerkiness in your Rigidbody’s movement.

  • None - No Interpolation is applied.

  • Interpolate - Transform is smoothed based on the Transform of the previous frame.

  • Extrapolate - Transform is smoothed based on the estimated Transform of the next frame.

  • Rigidbody - Unity Manual

2018-02-13 星期二

Matrix4x4

2018-02-03 星期六

C# 的委托:delegate Action Func predicate

struct & class

  • C# 中 Struct 与 Class 的区别,以及两者的适用场合 - cnblogs

  • class 是引用类型,struct 是值类型

  • class 有面向对象的扩展优势,struct 有性能优势

  • 将用于底层数据存储的类型设计为 struct,而将用于定义应用程序行为的类型设计为 class;如果对类型将来的应用情况不确定,应将其设计为 class

2018-01-27 星期六

Transform.parent & Transform.SetParent

Transform.parent

The parent of the transform. Changing the parent will modify the parent-relative position, scale and rotation but keep the world space position, rotation and scale the same.

Transform.SetParent

Set the parent of the transform. This method is the same as the parent property except that it is possible to make the Transform keep its local orientation rather than its global orientation. This is managed by setting the worldPositionStays parameter to false. When SetParent is called with only the single Transform argument the worldPositionStays argument is set to true.

2018-01-17 星期三

判断动画是否播放结束

三种方法:

  • FBX -> Animations -> Clips -> Events -> Add Event
  • Animator -> Exit Time
  • AnimatorStateInfo.normalizedTime

2018-01-16 星期二

Rotating an object in relation to its velocity

Rigidbody 的转向跟随其速度方向的实现采用这种方法:

物体移动方式

2018-01-13 星期六

Collider or Trigger?

Collider 和 Trigger 的区别?OnCollisionEnter 和 OnTriggerEnter 的区别?

OnCollisionEnter is called when this collider/rigidbody has begun touching another rigidbody/collider. In contrast to OnTriggerEnter, OnCollisionEnter is passed the Collision class and not a Collider. The Collision class contains information about contact points, impact velocity etc. If you don't use collisionInfo in the function, leave out the collisionInfo parameter as this avoids unneccessary calculations. Notes: Collision events are only sent if one of the colliders also has a non-kinematic rigidbody attached. Collision events will be sent to disabled MonoBehaviours, to allow enabling Behaviours in response to collisions.

OnTriggerEnter is called when the Collider other enters the trigger. This message is sent to the trigger Collider and the Rigidbody (if any) that the trigger Collider belongs to, and to the Rigidbody (or the Collider if there is no Rigidbody) that touches the trigger. Notes: Trigger events are only sent if one of the Colliders also has a Rigidbody attached. Trigger events will be sent to disabled MonoBehaviours, to allow enabling Behaviours in response to collisions. OnTriggerEnter occurs on the FixedUpdate after a collision. The Colliders involved are not guaranteed to be at the point of initial contact. Note: OnTriggerEnter is not technically part of Collision. It is a MonoBehaviour function.

readonly

The readonly keyword is a modifier that you can use on fields. When a field declaration includes a readonly modifier, assignments to the fields introduced by the declaration can only occur as part of the declaration or in a constructor in the same class.

The readonly keyword is used to declare a member variable a constant, but allows the value to be calculated at runtime. This differs from a constant declared with the const modifier, which must have its value set at compile time. Using readonly you can set the value of the field either in the declaration, or in the constructor of the object that the field is a member of. Also use it if you don't want to have to recompile external DLLs that reference the constant (since it gets replaced at compile time).

2018-01-11 星期四

坐标系转化

弧度与角度

float 值是否相等判定

2018-01-04 星期四

雾效

Sublime Text 文本不换行显示

"word_wrap": "false"

自定义宏

2017-12-27 星期三

物理引擎碰撞检测 & 网络编程算法

2017-12-24 星期日

NGUI 自适应屏幕

2017-12-23 星期六

Inspector 中的脚本勾选框

Animator.CrossFade

2017-12-06 星期三

游戏程序团队分工

一种游戏程序团队可能的分工

客户端1:负责战斗系统 客户端2:负责底层(网络、资源管理、热更等) 客户端3:UI类系统、AI 客户端4:UI类系统

服务端1:战斗系统 服务端2:底层 服务端3:功能类系统

2017-12-04 星期一

逻辑帧与渲染帧

性能优化

2017-12-02 星期六

Audio

  • Audio Reverb Zones 音频混响区的概念和用法没弄明白?(直接看 Unity Manual 吧)

2017-12-01 星期五

游戏程序员之路


Shader

2017-11-22 星期三

iOS 项目编译错误

编译 iOS 项目时报以下错误,可能与 Unity IAP 的 bug 有关,删除项目中的 link.xml 即可编译成功,其他设置无须改动。

Failed running /Applications/Unity/Unity.app/Contents/il2cpp/build/UnityLinker.exe --api=NET_2_0_Subset

2017-11-19 星期日

UGUI RectTransform

编译 Android 失败

idea 编译项目错误

2017-11-17 星期五

Unity 配置文件读取

[CreateAssetMenu(fileName = "NetworkConfig", menuName = "Proton/NetworkConfig", order = 0)]
public class NetworkConfig : ScriptableObject
{
    public string Host = "127.0.0.1";
    public int Port = 9527;
}

// 读取配置
NetworkConfig networkConfig = Resources.Load<NetworkConfig>("NetworkConfig");
Debug.Log(networkConfig.Host + ":" + networkConfig.Port);

2017-10-31 星期二

DDL for game database

CREATE TABLE `user` (
  `id` varchar(32) NOT NULL,
  `pw` varchar(32) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

CREATE TABLE `player` (
  `id` varchar(32) NOT NULL,
  `data` blob,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

2017-09-19 星期二

ASCII 码表

Frame Sync

2017-09-15 星期五

C# decompile

2017-09-12 星期二

MVC & MVVM & Unity 项目架构

2017-09-11 星期一

Splatoon

Client-Server Game Architecture

2017-09-09 星期六

uFrame

2017-09-06 星期三

Bombermaaan

UML

2017-09-04 星期一

Unity Trick

在 Scene 视图中快速无缝拼接贴图或者物体:

让粒子系统跟随 GameObject 旋转:

thrust_flare.particleSystem.startRotation = gameObject.transform.rotation.eulerAngles.y * Mathf.Deg2Rad;

Unity 平台依赖编译:

2017-08-31 星期四

mysql

Windows 上安装Mysql

Windows上安装Mysql相对来说会较为简单,你只需要在 MySQL 下载中下载windows版本的mysql安装包,并解压安装包。 双击 setup.exe 文件,接下来你只需要安装默认的配置点击"next"即可,默认情况下安装信息会在C:\mysql目录中。 接下来你可以通过"开始" =》在搜索框中输入 " cmd" 命令 =》 在命令提示符上切换到 C:\mysql\bin 目录,并输入一下命令:

mysqld.exe --console

如果安装成功以上命令将输出一些mysql启动及InnoDB信息。

TCP/IP port:3306

2017-08-30 星期三

Socket.Receive

Socket 客户端的接收字节流的方法,可以自动读取流中所有的可用数据(一个长度不确定的消息包的所有字节),前提是用于接收的字节数组 byte[] 大小够大(或者 ByteBuffer):

// Socket.​Receive
public int Receive (byte[] buffer);
// Returns: The number of bytes received.
// java.io.InputStream
public int read(byte[] b) throws IOException
// Returns: the total number of bytes read into the buffer, or -1 if there is no more data because the end of the stream has been reached.

2017-08-24 星期四

Using VS with Unity - Trouble Shooting

2017-08-18 星期五

Lua Editor

Lua 编辑器:ZeroBrane Studio

2017-08-17 星期四

热更新

  • 热更新的原理和过程: ⁃ 其实做热更的步骤不麻烦,因为Unity的c#类部分热更不了,那我们需要热更的就只有Lua代码部分了,当我们写完游戏测试OK了,就可以上线运营,并且在Web服务器上面部署最新的版本资源文件,我们就可以将Lua的代码编码后上传到Web服务器上面去,当游戏客户端启动的时候,它会启动解包流程、解包的资源一般都是当时做包时候的资源,到后面我们修改以后,它内部的资源可能已经不是最新的了,但是大部分可能是新的,只有少部分需要更新,那紧接着就启动更新流程,从Web服务器上面的资源配置列表里面,通过MD5/CRC比较查询到最新的资源,下载更新本地的文件,达到更新最新版的目的,游戏顺利启动。

接下来便要尝试代码热更新,让程序下载服务器上的lua文件,然后运行它。在说明热更新之前,需要先看看Unity3D热更新的一般方法。如下图所示,Unity3D的热更新会涉及3个目录。

热更新的过程:

游戏资源目录:里面包含Unity3D工程中StreamingAssets文件夹下的文件。安装游戏之后,这些文件将会被一字不差地复制到目标机器上的特定文件夹里,不同平台的文件夹不同,如下所示(上图以windows平台为例)

Mac OS或Windows:Application.dataPath + "/StreamingAssets";

IOS: Application.dataPath + "/Raw";

Android:jar:file://" + Application.dataPath + "!/assets/";

数据目录:由于“游戏资源目录”在Android和IOS上是只读的,不能把网上的下载的资源放到里面,所以需要建立一个“数据目录”,该目录可读可写。第一次开启游戏后,程序将“游戏资源目录”的内容复制到“数据目录中”(步骤1,这个步骤只会执行一次,下次再打开游戏就不复制了)。游戏过程中的资源加载,都是从“数据目录”中获取、解包(步骤3)。不同平台下,“数据目录”的地址也不同,LuaFramework的定义如下:

Android或IOS:Application.persistentDataPath + "/LuaFramework"

Mac OS或Windows:c:/LuaFramework/

调试模式下:Application.dataPath + "/StreamingAssets/"

注:”LuaFramework”和”StreamingAssets”由配置决定,这里取默认值

网络资源地址:存放游戏资源的网址,游戏开启后,程序会从网络资源地址下载一些更新的文件到数据目录。

这些目录包含着不同版本的资源文件,以及用于版本控制的files.txt。Files.txt的内容如下图所示,里面存放着资源文件的名称和md5码。程序会先下载“网络资源地址”上的files.txt,然后与“数据目录”中文件的md5码做比较,更新有变化的文件(步骤2)。

files.txt

LuaFramework的热更新代码定义在Assets\LuaFramework\Scripts\Manager\GameManager.cs,真正用到项目时可能还需少许改动。

2017-08-15 星期二

pbc

在 macOS 中编译 pbc

cloudwu/pbc#97

2017-08-10 星期四

2017-08-07 星期一

网络游戏编程资料

http://www.gad.qq.com/article/detail/28052 http://fabiensanglard.net/quake3/index.php