有关游戏进入动更机制流程的思考 (Unity)

主要流程状态

  • Init
  • LoadManifestVersion
  • CompareManifestVersion
  • LoadManifest
  • CompareManifest
  • Upgrade
  • AfterUpgrade
  • Unzip
  • AfterUnzip
  • Done

主要接口

m_AssetUpdateOp = Miaokids.Modules.ResourceDownloader.Instance.UpdateAssets (Miaokids.Utilities.Constants.updateManifestFile,
                settingManager.resourceUrl,
                false, false, true);
            yield return m_AssetUpdateOp;

Init

初始化

1 初始化下载路径

m_TemporaryPath = "/Projects/miaokidsmathpublic/miaokids/tmp/";
m_InstallPath = "/Users/tomyuan/Projects/miaokidsmathpublic/miaokids/install/"
m_ResourcePath = "/Users/tomyuan/Projects/miaokidsmathpublic/miaokids/resource/main/"
m_ManifestVersionFileName = "manifest_version/main.json"
m_ManifestFileName = "manifest/main.json"
m_DownloadUrl = "https://miaokids-xxxxxxx.aliyuncs.com/android/1.0.0/"

2 初始化参数

IgnoreCompareManifestVersion = false
KeepAlive = keepAlive;
EnablePing = enablePing;

LoadManifestVersion

m_DownloadSpeedCalculator.Reset ();

m_LoadLocalManifestVersionOp = FileManager.Instance.LoadFile (m_ManifestVersionFileName);

m_LoadRemoteManifestVersionOp = new AssetHttpDownloadOperation (m_DownloadUrl + m_ManifestVersionFileName);
m_LoadRemoteManifestVersionOp.EnableWriteFile = false;
m_LoadRemoteManifestVersionOp.RetainData = true;
m_LoadRemoteManifestVersionOp.Start ();

Unity下的Slider ScrollView

Slider ScrollView

如下图所示,主要制作可以左右滑动的ScrollView切屏幕效果

主要功能和设计思路

功能效果非常类似手机横滑切屏幕的效果,我们主要还是依托Unity的ScrollRect组件,然后水平方向我们通过计算滑动的距离和时间,判断是否进行切屏操作,再执行切屏过程中,滑动区域下方的导航点也会根据当前展示页面显示不同的激活状态。

Git push出现Could not resolve host问题解决

Could not resolve host:xxx 问题


当我们在使用git进行推送的时候有时会遇到Could not resolve host的问题,一般我们都会尝试重启网络再尝试push,这样无法从根本解决问题。目前还有一种更为有效的方式:通过改host配置文件来完成。

具体错误如下

git push origin channels/xxxx
fatal: unable to access 'https://git.dev.tencent.com/xxxx/xxxx.git/': Could not resolve host: git.dev.tencent.com

首先我们ping无法resolv的host

ping git.dev.tencent.com
PING git.tencentcloud.coding.net (118.25.166.124): 56 data bytes
64 bytes from 118.25.166.124: icmp_seq=0 ttl=51 time=34.578 ms
64 bytes from 118.25.166.124: icmp_seq=1 ttl=51 time=36.573 ms

然后修改host文件即可

sudo vi /etc/hosts
# 文件增加一行 118.25.166.124 git.tencentcloud.coding.net #git.tencentcloud.coding.net

如果还不可以需要执行如下命令

git config --global --unset http.proxy
git config --global --unset https.proxy 

搞定

补充
有朋友留言如下:
感觉是coding被收购后内部在维护,

git.coding.net和git.dev.tencent.com原来是指向相同的服务器,

试了下面这样,发现也可以

git remote add coding https://git.coding.net/xxxx/xxxx.git/
git push coding master

MiaoKids Artificial Intelligence Circuit

芯片智能交互技术


MAIC主要实现了视觉、听觉、触觉的多重感官刺激学习的功能设计,让儿童在学习过程中始终保持兴趣。
优学猫整个研发团队以孩子为中心,以兴趣为导向;遵循技术是服务于孩子;尊重孩子的天性同时培养孩子对于学习的兴趣。

优学猫视觉体验

鲜艳的色彩,丰富的动作对于儿童有非常大的吸引力,不管是看动画片也好,还是卡通故事也好都很好的证明了这个事实;而在科技日新月异的今天,孩子所能接受到的信息早已不是已为父辈的我们儿时接受的那么般匮乏。以《优学猫数学》为例,优学猫团队为了将小朋友带入一个美妙的数学王国,我们采用了目前市场化非常成熟的Unity引擎进行整个产品的客户端开发工作,针对低年龄段儿童的特性,我们放弃了3D,选择2D开发;Unity在当时针对2D和Texture2D的很多功能都不尽完善,所以整个团队针对各种需求写出了一些专用的Unity工具和一些提升效果和纹理功能的Shader;为了使得动画展示更加丰富,使用Spine的骨骼动画,可以在使用较少资源的情况下,将效果最大化,骨骼动画其中用到了不少矩阵运算的知识,主要为了可以向量化的支持关节父子节点直接的变化。然后通过Unity将图片与动画有机的结合在一起,最终将美妙的数学王国呈现给小朋友。

优学猫听觉体验

除了色彩和动画,声音对于儿童也是必不可少的,舒缓的背景音乐和亲和的提示音可以给予小朋友安全感;而有趣的音效可以带给小朋友快乐。优学猫系列产品从声音体验这个角度而言,也做了很多的功课。在一些需要的场景,我们使用到了3D立体音效果,3D立体声和2D声不同的地方是它是会随着距离衰减的,距离越近声音越大,距离越远声音越小。而在进行游戏题目的过程中,每一道题目我们会根据小朋友答题的具体情况提示不同的声音,时而鼓励,时而启发。中国的家长一般非常重视孩子的双语教育,而优学猫为了满足这个需要,增加了语言切换的功能,在游戏内部可以无缝的在中文和英语下进行切换。整个技术开发的过程中,为了协调背景声音、旁白语音以及音效等多类声音,保证他们之间不会混淆,在多种声音覆盖的情况下突出重点,我们处理了音高和音量;在录音的部分,为了提高声音品质,也对所录的音频文件进行了音高和去噪处理(一般是采用一些滤波的方法,比如高斯滤波);除了目前所展现出来的,还有很多会继续开发和完善的部分,比如我们可以让家长录制自己鼓励声音,然后对在游戏的过程中播放家长的鼓励音,小朋友必定会更加高兴。有了家长的音频如果数据足够时,我们可以使用WaveNet进行语音合成功能的开发,一般语音合成主要使用“长短期记忆网络”(LSTM),而WaveNet是通过空洞卷积神经网络来实现的。

优学猫触觉体验

小朋友一般都有很多自己的玩具,一个起到了陪伴作用,另外就是小朋友可以通过接触感受到触感,触觉是人类七大感官之一,也是人类大脑重要的信息通道,从小培养孩子的触觉,有助于大脑的发育。优学猫是一个有实体积木的产品,不管从本身硬件板子的设计还是到数学积木、英语积木,我们考虑到每一个细节,比如工业设计模型的倒角,再到每个积木块的大小和材质,甚至每一条愣,每一个角度都经过认真打磨,在保证小朋友安全使用为第一前提的基础上,也仅最大的可能提高积木的触感。小朋友在进行优学猫学习和游戏的过程中,眼睛在屏幕和实体积木中来回切换,小朋友也会主动的进行思考,促进大脑的发育,同时声音和画面也会源源不断的传输信息给小朋友,优学猫从而做到增强小朋友手眼协调,脑力锻炼的能力,也更多元化的提供信息给小朋友。

优学猫智能

当今中国是一个人工智能大国,人工智能作为当今社会非常先进的生产力已经渗透到了各个领域,同样教育领域也不例外。优学猫也做到与时俱进,为幼儿教育的智能化出一份力,优学猫从下面几个角度做到了智能化,同样也会继续提高和努力。

  • 大数据与数据智能
    用户每天都会累计使用优学猫完成近千万级别的交互,做数据挖掘的一般常说:Data is rich, Information is pool,大概意思就是数据很多,但是有用的信息却很少,所以对这些数据进行挖掘是非常有必要的,不管为了家长更好的了解孩子还是为了企业的发展方向做参考。而在做具体分析的时候,我们一般会经过数据的收集和整理,再通过各种算法对已经收集好的信息做处理。

  • 语音智能
    优学猫英语在语音智能方面做过实践,目前人工智能语音方面有几个方向:语音识别、语音合成、自然语音处理等等,而优学猫英语使用了语音识别的技术,这里采用了CMU的sphinx开源算法,我们会对小朋友的录音先进行预处理,比如降噪,判别声音端点等等;然后对预处理后的声音进行特征提取,去除对于语音识别无用的信息,特征提取一般采用Mel频率倒谱系数(MFCC)来完成,首先将时域通过快速傅立叶变换转成频域,然后卷积处理;有了特征量之后,优学猫根据训练语音库的特征参数训练出声学模型参数,一般都采用隐马尔可夫模型进行声学模型建模,最终我们可以将声音处理成音素,再针对所给的音素集合和需要配对的声音进行匹配算法进行打分。

Git合并

一般情况下,我们使用merge命令即可合并两个branch,比如现在有两个Branch,一个是branchA,一个是branchB。现在我正处在BranchA,需要合并BranchB,只需要执行

git branch merge BranchB

解决冲突


我们使用代码管理工具的时候,总不可避免的会遇到代码冲突,有关代码冲突的相关介绍可以这里了解冲突时的分支合并,对于更复杂的冲突合并,我们可以借助Source Tree进行解决。
当我们遇到下面信息的时候,就需要手动进行冲突的解决。

CONFLICT (content): Merge conflict in hello.rb
Automatic merge failed; fix conflicts and then commit the result.

中断一次合并

当然遇到了冲突,我们也可以选择中断这次合并,通过下面命令,在工作目录中有未储藏、未提交的修改时它不能完美处理,除此之外它都工作地很好。

git merge --abort

如果因为某些原因你发现自己处在一个混乱的状态中然后只是想要重来一次,可以执行

git reset --hard HEAD

回到之前的状态或其他你想要恢复的状态。 请牢记这会将清除工作目录中的所有内容,所以确保你不需要保存这里的任意改动。

如果你想要在最终提交前看一下我们这边与另一边之间实际的修改,你可以使用 git diff 来比较将要提交作为合并结果的工作目录与其中任意一个阶段的文件差异。具体使用方法可以参考git-diff

同时我们可以使用下面指令来来清理我们为手动合并而创建但不再有用的额外文件。

git clean -f

撤销合并


我们已经知道如何创建一个合并提交,但有时出错是在所难免的。
我们有两种方法来解决这个问题,这取决于你想要的结果是什么
方法1
reset –hard
这个方法的缺点是它会重写历史,在一个共享的仓库中这会造成问题的。 用简单的话说就是如果其他人已经有你将要重写的提交,你应当避免使用 reset。 如果有任何其他提交在合并之后创建了,那么这个方法也会无效;移动引用实际上会丢失那些改动。
方法2 还原提交
$ git revert -m 1 HEAD

合并指定分支单个文件


# git checkout --patch branchB xxxx

合并指定commit


  • cherry pick 合并单个 commit
    git checkout master
    git cherry-pick xxxxx

Markdown基本语法

标题


在想要设置为标题的文字前面加#来表示
一个#是一级标题,二个#是二级标题,以此类推。支持六级标题。

# 这是一级标题
## 这是二级标题
### 这是三级标题
#### 这是四级标题
##### 这是五级标题
###### 这是六级标题

字体


  • 加粗
    要加粗的文字左右分别用两个*号包起来
  • 斜体
    要倾斜的文字左右分别用一个*号包起来
  • 斜体加粗
    要倾斜和加粗的文字左右分别用三个*号包起来
  • 删除线
    要加删除线的文字左右分别用两个~~号包起来
**这是加粗的文字**
*这是倾斜的文字*`
***这是斜体加粗的文字***
~~这是加删除线的文字~~

引用


在引用的文字前加>即可。引用也可以嵌套,如加两个>>三个>>>
n个等等

>这是引用的内容
>>这是引用的内容
>>>>>>>>>>这是引用的内容

分割线


三个或者三个以上的 – 或者 * 都可以。

---
----
***
*****

图片


![图片alt](图片地址 ''图片title'')
图片alt就是显示在图片下面的文字,相当于对图片内容的解释。
图片title是图片的标题,当鼠标移到图片上时显示的内容。title可加可不加
例如
![blockchain](http://tomyuan.cn/blog/wp-content/uploads/2017/04/0068KyMWly8fdm3fcgzpzj30hr0dcmz1.jpg "TomYuan")

超链接


[超链接名](超链接地址 "超链接title")
title可加可不加
[简书](http://jianshu.com)
[百度](http://baidu.com)

列表


无序列表用 – + * 任何一种都可以

- 列表内容
+ 列表内容
* 列表内容

注意:- + * 跟内容之间都要有一个空格

表格


表头|表头|表头
---|:--:|---:
内容|内容|内容
内容|内容|内容

第二行分割表头和内容。
- 有一个就行,为了对齐,多加了几个
文字默认居左
-两边加:表示文字居中
-右边加:表示文字居右
注:原生的语法两边都要用 | 包起来。此处省略

代码


为了防止转译,前后三个反引号处加了小括号,实际是没有的。这里只是用来演示,实际中去掉两边小括号即可

(```)
  代码...
  代码...
  代码...
(```)

Unity下使用HTTPS

背景说明


Google表示,为保证用户数据和设备的安全,针对下一代 Android 系统(Android P) 的应用程序,将要求默认使用加密连接,这意味着 Android P 将禁止 App 使用所有未加密的连接,因此运行 Android P 系统的安卓设备无论是接收或者发送流量,未来都不能明码传输,需要使用下一代(Transport Layer Security)传输层安全协议,而 Android Nougat 和 Oreo 则不受影响。
因此在Android P 中使用Http请求会遇到如下错误

W/System.err: java.io.IOException: Cleartext HTTP traffic to **** not permitted

使用OKHttp请求则出现

java.net.UnknownServiceException: CLEARTEXT communication ** not permitted by network security policy

此处需要注意的是即便是Web View也是需要https请求。
针对Android而言有一下3中解决方法

  • APP改用https请求
  • targetSdkVersion 降到27以下
  • 在 res 下新增一个 xml 目录,然后创建一个名为:network_security_config.xml 文件(名字自定) ,内容如下,大概意思就是允许开启http请求
    <?xml version="1.0" encoding="utf-8"?>
    <network-security-config>
    <base-config cleartextTrafficPermitted="true" />
    </network-security-config>

    然后在APP的AndroidManifest.xml文件下的application标签增加以下属性

    <application
    ...
    android:networkSecurityConfig="@xml/network_security_config"
    ...
    />

    Unity使用HTTPS


    #if !UNITY_WSA_10_0 && !UNITY_WINRT_8_1 && !UNITY_WSA && !UNITY_WEBPLAYER
    #define SUPPORT_SSL
    #endif
    ...
    using System.Net.Security;
    using System.Security.Cryptography.X509Certificates;
    using System.Threading;
    ...
    #if SUPPORT_SSL
    private bool MyRemoteCertificateValidationCallback(System.Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
    bool isOk = true;
    // If there are errors in the certificate chain,
    // look at each error to determine the cause.
    /*if (sslPolicyErrors != SslPolicyErrors.None)
    {
        for (int i = 0; i < chain.ChainStatus.Length; i++)
        {
            if (chain.ChainStatus[i].Status == X509ChainStatusFlags.RevocationStatusUnknown)
            {
                continue;
            }
            chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
            chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
            chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 1, 0);
            // Note: change flags to X509VerificationFlags.AllFlags to skip all security checks
            chain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;
            bool chainIsValid = chain.Build((X509Certificate2)certificate);
            if (!chainIsValid)
            {
                isOk = false;
                break;
            }
        }
    }*/
    return isOk;
    }
    #endif
    ...
    #if SUPPORT_SSL
    if (m_DownloadUrl.ToLower().StartsWith("https://"))
    {
    ServicePointManager.ServerCertificateValidationCallback = MyRemoteCertificateValidationCallback;
    }
    #endif

    针对WWW的GET请求我们也需要进行处理,我们可以使用WebClient().DownloadString的方法来完成

    ...
    #if SUPPORT_SSL
    if (m_DownloadUrl.ToLower().StartsWith("https://"))
    {
    ServicePointManager.ServerCertificateValidationCallback = MyRemoteCertificateValidationCallback;
    }
    #endif
    try {
    mes = new System.Net.WebClient().DownloadString(m_DownloadUrl);
    } catch (Exception e) {
    m_Error = e.Message;
    }
    ...

iOS .a文件生成指令

xcodebuild clean -project bluetooth.xcodeproj
xcodebuild -configuration Release -sdk iphonesimulator -arch i386 -project bluetooth.xcodeproj
mv build/Release-iphonesimulator/libbluetooth.a my/libbluetooth_i386.a

xcodebuild clean -project bluetooth.xcodeproj
xcodebuild -configuration Release -sdk iphonesimulator -arch x86_64 -project bluetooth.xcodeproj
mv build/Release-iphonesimulator/libbluetooth.a my/libbluetooth_x86_64.a

xcodebuild clean -project bluetooth.xcodeproj
xcodebuild -configuration Release -sdk iphoneos -arch armv7 -project bluetooth.xcodeproj
mv build/Release-iphoneos/libbluetooth.a my/libbluetooth_armv7.a

xcodebuild clean -project bluetooth.xcodeproj
xcodebuild -configuration Release -sdk iphoneos -arch armv7s -project bluetooth.xcodeproj
mv build/Release-iphoneos/libbluetooth.a my/libbluetooth_armv7s.a

xcodebuild clean -project bluetooth.xcodeproj
xcodebuild -configuration Release -sdk iphoneos -arch arm64 -project bluetooth.xcodeproj
mv build/Release-iphoneos/libbluetooth.a my/libbluetooth_arm64.a

lipo -create my/libbluetooth_arm64.a my/libbluetooth_armv7.a my/libbluetooth_armv7s.a my/libbluetooth_x86_64.a -output my/libbluetooth.a

BLE中writeValue的方式

BLE特征属性

这里提到的特征属性在iOS的BLE中值得是CBCharacteristic类型的properties的属性,我们参考下面的代码看

/*!
 *  @enum CBCharacteristicProperties
 *
 *  @discussion Characteristic properties determine how the characteristic value can be used, or how the descriptor(s) can be accessed. Can be combined. Unless
 *              otherwise specified, properties are valid for local characteristics published via @link CBPeripheralManager @/link.
 *
 *  @constant CBCharacteristicPropertyBroadcast                     Permits broadcasts of the characteristic value using a characteristic configuration descriptor. Not allowed for local characteristics.
 *  @constant CBCharacteristicPropertyRead                          Permits reads of the characteristic value.
 *  @constant CBCharacteristicPropertyWriteWithoutResponse          Permits writes of the characteristic value, without a response.
 *  @constant CBCharacteristicPropertyWrite                         Permits writes of the characteristic value.
 *  @constant CBCharacteristicPropertyNotify                        Permits notifications of the characteristic value, without a response.
 *  @constant CBCharacteristicPropertyIndicate                      Permits indications of the characteristic value.
 *  @constant CBCharacteristicPropertyAuthenticatedSignedWrites     Permits signed writes of the characteristic value
 *  @constant CBCharacteristicPropertyExtendedProperties            If set, additional characteristic properties are defined in the characteristic extended properties descriptor. Not allowed for local characteristics.
 *  @constant CBCharacteristicPropertyNotifyEncryptionRequired      If set, only trusted devices can enable notifications of the characteristic value.
 *  @constant CBCharacteristicPropertyIndicateEncryptionRequired    If set, only trusted devices can enable indications of the characteristic value.
 *
 */
typedef NS_OPTIONS(NSUInteger, CBCharacteristicProperties) {
    CBCharacteristicPropertyBroadcast                                               = 0x01,
    CBCharacteristicPropertyRead                                                    = 0x02,
    CBCharacteristicPropertyWriteWithoutResponse                                    = 0x04,
    CBCharacteristicPropertyWrite                                                   = 0x08,
    CBCharacteristicPropertyNotify                                                  = 0x10,
    CBCharacteristicPropertyIndicate                                                = 0x20,
    CBCharacteristicPropertyAuthenticatedSignedWrites                               = 0x40,
    CBCharacteristicPropertyExtendedProperties                                      = 0x80,
    CBCharacteristicPropertyNotifyEncryptionRequired NS_ENUM_AVAILABLE(10_9, 6_0)   = 0x100,
    CBCharacteristicPropertyIndicateEncryptionRequired NS_ENUM_AVAILABLE(10_9, 6_0) = 0x200
};

所以如何使用characteristicWriteType通过如下代码即可控制

// 通过characteristic判断
if (self.characteristic.properties & CBCharacteristicPropertyWriteWithoutResponse) {
    self.characteristicWriteType = CBCharacteristicWriteWithoutResponse;
}
if (self.characteristic.properties & CBCharacteristicPropertyWrite) {
    self.characteristicWriteType = CBCharacteristicWriteWithResponse;
}

此处我们以一个设备的特征进行举例,特征具体为

<CBCharacteristic: 0xxxxxxxxx, UUID = XXXX, properties = 0x18, value = <aaxxxxx0 00xxxx00 xx>, notifying = YES>

然后我们拿到properties为0x18,我们进行特征计算得到如下效果:

>>> 0x18 & 4
0
>>> 0x18 & 8
8

所以当前设备需要使用CBCharacteristicPropertyWrite而不是without的WriteValue方式

CodeVS Problem 01 – Cantor表

Cantor表
现代数学的著名证明之一是Georg Cantor证明了有理数是可枚举的。他是用下面这一张表来证明这一命题的: 1/1 1/2 1/3 1/4 1/5 … 2/1 2/2 2/3 2/4 … 3/1 3/2 3/3 … 4/1 4/2 … 5/1 … … 我们以Z字形给上表的每一项编号。第一项是1/1,然后是1/2,2/1,3/1,2/2,…

输入描述 Input Description
整数N(1≤N≤10000000)

输出描述 Output Description
表中的第N项

样例输入 Sample Input
7

样例输出 Sample Output
1/4

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
// 制定移动规律
enum Direct {
	RIGHT = 1,
	LEFTDOWN = 2,
	DOWN = 3,
	RIGHTUP = 4
};

std::vector Locus(int step) {
	std::vector directs;
	int currentTime = 1;
	int l = 1;
	for (int i = 1; i <= step;) {
		if (l % 4 == 1) {
			// 右
			directs.push_back(RIGHT);
			i = i + 1;
		} else if (l % 4 == 3) {
			// 下
			directs.push_back(DOWN);
			i = i + 1;
		} else if (l % 4 == 2) {
			// 左下
			for (int j = 0; j < currentTime; j++) {
				directs.push_back(LEFTDOWN);
				i = i + 1;
				if (i == step + 1) {
					break;
				}
			}
			currentTime = currentTime + 1;
		} else if (l % 4 == 0) {
			// 右上
			for (int j = 0; j < currentTime; j++) { directs.push_back(RIGHTUP); i = i + 1; if (i == step + 1) { break; } } currentTime = currentTime + 1; } l = l + 1; } return directs; } int main() { // 定义默认 X = 1, Y = 1 int X = 1, Y = 1; int step = 0; cin >> step;
	std::vector directs = Locus(step - 1);
	for (int i = 0; i < directs.size(); i++) {
		Direct direct = directs[i];
		if (direct == RIGHT) {
			X = X + 1;
		} else if (direct == LEFTDOWN) {
			X = X - 1;
			Y = Y + 1;
		} else if (direct == DOWN) {
			Y = Y + 1;
		} else if (direct == RIGHTUP) {
			X = X + 1;
			Y = Y - 1;
		}
	}
	cout << Y << "/" << X;
}




Unity 技术积累

  • Unity中Android和iOS的StreamingAsset路径
  • string StreamAssetPath {
        get {
            string filePath = "";
            #if UNITY_ANDROID && !UNITY_EDITOR
                filePath = "jar:file://" + Application.dataPath + "!/assets/" + flodername + "/";
            #elif UNITY_IPHONE && !UNITY_EDITOR
                filePath = Application.dataPath + "/Raw/";
            #elif UNITY_STANDALONE_WIN || UNITY_EDITOR
                filePath = "file://" + Application.dataPath + "/StreamingAssets" + "/" + flodername + "/";
            #else
                // TODO
            #endif
            return filePath;
        }
    }
    

    机器学习 – 正规方程法(Unity版本)

    // @author TomYuan
    using UnityEngine;
    using System.Collections;
    using LinearAlgebra;
    using UnityEngine.UI;
    
    public class Main : MonoBehaviour {
    
    	void Start () {
    		// For Example
    		// Predict The House Value
    		// Training Data Set
    		/**
    		 *  RoomNumber    Feet(2)    Coordinates   Cost
    		 *      3          2000           1        250,000
    		 *      2          800            2        300,000
    		 *      2          850            1        150,000
    		 *      2          550            1         78,000
    		 *      4          2000           3        150,000
    		 */
    		/**
    		 *  Cal RoomNumber(3)   Feets(2000)  Coordinates(2)
    		 */
    		// Min = (X(T)*X)(-1)*X(T)*y
    		// f(x) = a + bx1 + cx2 + dx3
    		Matrix X = Matrix.Create (5, 4, 
    			           new double[] {
    							1, 3, 2000, 1,
    							1, 2, 800, 2,
    							1, 2, 850, 1,
    							1, 2, 550, 1,
    							1, 4, 2000, 3
    						});
    		Matrix y = Matrix.Create (5, 1, 
    			            new double[] {
    							250000,
    							300000,
    							150000,
    							78000,
    							150000
    						});
    		Matrix result = ((X.Transpose () * X).Inverse ()) * X.Transpose () * y;
    		// Cal Result
    		Matrix example = Matrix.Create(1, 4, new double[] {
    			1, 3, 2000, 2
    		});
    		// double cost = result.Elements[0, 0] + result.Elements[1, 0] * 3 + result[2, 0] * 2000 + result[3, 0] * 2;
    		// Debug.Log ("RoomNumber(3)   Feets(2000)  Coordinates(2)'s Cost:" + Mathf.Ceil((float)cost));
    		Matrix cost_matrix = example * result;
    		Debug.Log ("RoomNumber(3)   Feets(2000)  Coordinates(2)'s Cost:" + Mathf.Ceil((float)cost_matrix.Elements[0, 0]));
    		GameObject.Find ("Text").GetComponent ().text = "RoomNumber(3)   Feets(2000)  Coordinates(2)'s Cost:" + Mathf.Ceil ((float)cost_matrix.Elements [0, 0]);
    			
    	}
            ......
    }
    

    技术备忘录

    1 Unity调试技巧:Android下主要通过Android工程的Log来进行调试

    然后通过这里进行观察即可

    IOS中Unity调试方式也是一样,在XCode中观察输出的调试信息进行调试。
    2 有关Lua使用的注意事项,注意Git更新代码后,无论是否有新文件或者新类的添加都需要进行Clear Lua操作,确定保证Lua中Binding没有问题。

    3 Unity插件 – Haste

    Egret – WebGL下显示错误的问题

    Canvas中setTransform

    绘制一个矩形,通过 setTransform() 重置并创建新的变换矩阵,再次绘制矩形,重置并创建新的变换矩阵,然后再次绘制矩形。
    setTransform() 允许您缩放、旋转、移动并倾斜当前的环境。

    
    // a 表示水平旋转绘图
    // b 表示水平倾斜绘图
    // c 表示垂直倾斜绘图
    // d 表示垂直缩放绘图
    // e 表示水平移动绘图
    // f 表示垂直移动绘图
    context.setTransform(a,b,c,d,e,f);
    

    drawTexture

    
    /**
     * 绘制材质
     */
    WebGLRenderContext.prototype.drawTexture = function (texture, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, destWidth, destHeight, textureWidth, textureHeight, meshUVs, meshVertices, meshIndices, bounds) {
        var buffer = this.currentBuffer;
        if (this.contextLost || !texture || !buffer) {
            return;
        }
        if (meshVertices && meshIndices) {
            if (this.vao.reachMaxSize(meshVertices.length / 2, meshIndices.length)) {
                this.$drawWebGL();
            }
        }
        else {
            if (this.vao.reachMaxSize()) {
                this.$drawWebGL();
            }
        }
        if (meshUVs) {
            this.vao.changeToMeshIndices();
        }
        var transform = buffer.globalMatrix;
        var alpha = buffer.globalAlpha;
        var count = meshIndices ? meshIndices.length / 3 : 2;
        // 应用$filter,因为只可能是colorMatrixFilter,最后两个参数可不传
        this.drawCmdManager.pushDrawTexture(texture, count, this.$filter);
        this.vao.cacheArrays(transform, alpha, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, destWidth, destHeight, textureWidth, textureHeight, meshUVs, meshVertices, meshIndices);
    };
    

    texture, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, destWidth, destHeight, textureWidth, textureHeight, meshUVs, meshVertices, meshIndices, bounds

    关于我

    个人简介


    袁博,男,1990年3月31日,大学本科学历,大学其间多次参加信息竞赛并获奖;毕业后在腾讯(北京)工作,主要从事社交及电商开发工作;2013年加入游戏创业团队担任游戏开发工程师;后加入北京优扬传媒有限公司担任主程开发工作,主要负责前后端架构及功能研发;2018年6月加入北京小嗨乐学科技有限公司担任CTO,主要负责优学猫系列产品的研发和维护工作。

    大事记


    • 2017.06.04
      买车了,最近一直开车,希望可以一路平安,一切以安全为重。最近更多的研究方向偏向人工智能和机器学习了。希望可以慢慢进步,与业内的各位朋友多多交流!
    • 2017.06.14
      NBA勇士冠军!!!!
    • 2017.06.04
      创业进行中,加油!!!
    • 2018.09.26
      马上就要当爸爸了,继续努力!!
    • 2019.02.25
      有贴心小棉袄了,太开心了!
    • 2019.05.08
      妞妞已经百天了,希望你可以健健康康长大,爸爸爱你!

      写于2016年9月,也希望写给多年后的自己!


       在整个之前,我先聊下自己的游戏之旅吧!希望朋友们也可以留言给我聊聊自己的游戏之路。上大学期间,我就一直爱好着游戏开发,学习计算机其实也是因为自己的游戏情节,小时候玩的《仙剑奇侠传》和《红色警戒》,后来玩的《魔兽争霸3》到现在都历历在目,似乎现在玩游戏很难找到曾经的那个感觉了。说回游戏开发,记得刚上大学我我没有接触过什么游戏引擎,只是觉得可以自己做出一个自己的游戏非常的牛掰。那时使用的IDE还是VC6.0(是多么让人回味啊),文档方面主要靠着MSDN以及Windows API,花费很大的力气也就做些小玩意,更不要说理解什么是游戏引擎,那时觉得自己可以学习到事件回调、游戏循环等概念就非常知足了。

       一段时间之后发现,无论怎么写,做的无外乎也就是俄罗斯方块等简单的游戏(其实也不简单)。这些游戏和我自己梦想的游戏,比如说《仙剑奇侠传》、《金庸群侠传》相距甚远。所以查阅了不少资料,了解到DirectX还是非常好的,其实我这里是先接触DirectX的,后来毕业后做cocos2d-x,才开始研究OpenGL的。现在清晰的记得研究DirectX的岁月,那个时候没有什么相关的中文文档,只能硬着头皮看着英文文档,了解了什么是渲染,什么是光照等等。这个学习过程持续了一段时间,自己也按照样例做了些不大不小的东西。

       后来不知是什么时候就喜欢在各种地方下载源码,尤其是游戏相关的,不管是什么语言一概下载下来,说来惭愧,到现在还有很多没有看,也不知道去哪里了,当然也是因为这个习惯,发现了云风的“风魂”的源码,了解到游戏引擎这个奇妙的东西,“风魂”主要是以C来完成的,里面还混合了汇编加速,当时读起来真心觉得非常的痛苦,但是对自己的能力获得或少还是有所提高,看了一段时间差不多就大二了,因为要成为学长了,就有了自己组织学弟学妹来做一个游戏引擎的打算,当然那时候很天真,没想到困难有后面那么多,经过老师的同意,组织了十个下一级的学生,每天晚上聚在一起给他们讲C语言,然后一起聊游戏,聊人生。那段日子可以说痛并快乐着,后来游戏引擎有了一点点模样,但是大家都有自己的事情,自己这方面已经开始在外实习和比赛,游戏引擎的事情就这么搁置了,下面就说说我们比赛和工作经历。

       其实我参加的都是算法方面的编程比赛,那会儿还天真的以为算法玩的很好就会做游戏了,可是后来才明白,只明白算法是远远不够的。那会儿主要参加的就是“百度之星”和“Topcoder”,也拿了一些名次,现在能记住的就是因为时差原因,Topcoder的比赛一般在深夜,我就自己熬着夜,提交代码之后,相互找别人代码的问题(challenge)。做过ACM,反正那阶段就不断的调试代码找题做吧。

       说说自己的工作经历,自己开始的工作和游戏关系也不大,大一下半学期就兼职给一个明星维护网站工作以及相关的网站开发任务。后来由于一些原因就不干了,可能是真心不喜欢,随后在4399实习做了一段时间的服务器,还记得是用erlang,后来就在腾讯做Web开发了,这期间其实一直工作中一直没有做过什么游戏,还是因为自己对游戏的热爱,离开了腾讯。

       之后辗转反侧进了游戏公司,第一家游戏公司是一家创业型的公司,用的就是cocos,还记的那个时候的版本是1.x版本吧,去了之后既没有签合同,薪资也少的可怜。因为我当时在西二旗住,公司坐标是石景山,每天6点不到就出门了,然后基本上每天都快12点到家。但是我依旧是快乐的,那种刚刚进入游戏行业的兴奋感,现在还有印象,但是公司方面似乎就我一个外人,剩下的主程、美术以及策划是一个团队出来的,对于所有东西防我和防狼一样,没有网络,所有的代码也没有对我开源,现在其实我也能够理解当时的情况,但是当时我觉得过的很憋屈,于是帮助他们完成了聊天模块和背包模块之后,一个月吧,我就辞职了。当然最后也没有给我一分钱,但是也是心存感激的,从那时我进入了cocos领域,开始了很长很长的游戏旅途,一直到现在。

       在新的公司,同事们一起完成了适配、架构、网络、支付等等各种工作,也克服了各种困难,经历了整个手游从蓝海到红海的过程。后来H5火了,当然现在依旧火,那是为了配合公司的工作,就用cocos-js版本做过一些项目,大概有3、4个游戏吧,但是Android上都卡的要死,公司就放弃了。之后出来了一款大家都耳熟能详的游戏佳作:刀塔传奇,于是经过我们的努力,将整个的开发流变更为了cocos2d + lua的方式,当然没有用quick,开发速度大大加快,也享受到了技术带来的革新。之后的做了几个游戏,产品技术问题都不大,但是由于挖坑和后期的运营确实不擅长于是结局就是没有成功。

       挣扎了一段时间更换了工作,在新的环境中发现了一个名字叫“Egret(白鹭)”的H5引擎火了,抱着看一看的心态下载了,用户体验确实远远强于cocos,这个也应该至少是一年以前的事情了,经过了一年的体验,当然真正的使用时间也不长,因为公司的业务暂时也不是H5为主,所以在公司即将开展H5项目之机会,想完成一个新的框架和接口,使得类似我这样的cocos2d-x开发者可以更加快速的上手做自己的H5游戏,希望可以和大家一起学习和进步。