11RIA 闪客社区 - 专注Flash技术,做全球最大的Flash AS AIR及周边技术开发者社区

搜索
查看: 256|回复: 32

[燃烧的水月] AS3转码其他语言,工具开发记录

[复制链接]

签到天数: 2 天

发表于 2018-11-9 12:17:01 | 显示全部楼层 |阅读模式

【游客模式】——注册会员,加入11RIA 闪客社区吧!一起见证Flash的再次辉煌……

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
本帖最后由 general_clarke 于 2018-11-14 14:21 编辑

【序】

楼主从FlashMX、AS2时开始使用flash解决方案,目前是杭州一家小型游戏开发公司的CTO。

在相当数量同业者追逐热门语言并为语言特性和编译工具头疼时,另一群人把时间和精力投入到算法和架构上。
有可能的话,我希望可以将一门语言一直专精下去。

我司长期专精于as3,从flash小游戏到AIR手游,业内长期唱衰flash并未影响到我司收入和规模扩张。
到发此帖时,AIR和adobe技术仍是我司赖以生存的资金来源。

直到两件事的发生让我意识到AIR虽然目前仍是稳定完善的解决方案,然为了公司长远发展,必须留一条后路才行。

一件是AIR28被苹果拒审。此问题是AIR运行时调用了苹果隐藏的API导致。
在这个问题上adobe在AIR29版本作出了不甚完美的修复,直到AIR30彻底解决花费了我们作为一款在线项目难以接受的时间。
我司有出色的工程师,手工修改了苹果AIR运行时库,比同业者提前成功上传,但是这让我们不得不考虑如果下次出现相同现象是否也能顺利解决。

第二件,我司位于杭州,在一个月前因希望扩张项目组招聘更多as程序员,
然即使在招聘网站发布广告、群发布广告(感谢T大设置了群公告)
实际数周内应聘者寥寥,少数的面试者水平也无法满足新项目需求。

因此,为了科学的可持续发展,比起老牌的C++/Cocos和新兴的H5,我看中了效率好功能强的C#+Unity解决方案。

此帖放在水区作为日记形式,记录从AS3转换C#的大事小事。此工具仍在制作,虽然楼主不认为此方案有什么问题,
如中途出了意外,这篇便是一篇探坑作。


因涉及一整个新项目,不出意外将不定期更新数个月到半年时间。
这个记录谈不上技术分享,因为想到哪写到哪,也有一些楼层水分含量较高,随时会编辑掉错字和查缺补漏。
如版主认为需要迁区请随意






评分

参与人数 1银子 +88 金子 +1 贡献 +1 威望 +1 收起 理由
TKCB + 88 + 1 + 1 + 1 欢迎将军大神分享技术,,AS3技术人才真的.

查看全部评分

本帖被以下淘专辑推荐:

签到天数: 2 天

 楼主| 发表于 2018-11-9 12:58:27 | 显示全部楼层
本帖最后由 general_clarke 于 2018-11-10 12:07 编辑

方案是“代码转换”,不是“我要转行”
要被改变的只有as3,
从var a:int = 10;通过工具转变为int a = 10;

我们不算第一个吃螃蟹,诸位可能听过LayaFlash,这是个as3项目转换成H5项目的技术
那么,为什么不直接用其他语言重写一次而是搞转码工具?


as3项目是公司的流水项目。作为程序员可以通过跳槽放弃原有项目改变使用技术,作为公司不行。为了公司人的衣食住行,as3项目必须维护下去。
那么,
如果新项目直接使用C#编写,我们会面临以下问题

我们有不少旧库。
旧库是公司核心竞争力之一,包含我们积累下的优秀物理、美术、通信、调试代码、编辑器和工具链。


首先
如果旧库完全放弃,新项目老项目使用不同主程不同技术不同库,
因我们对新技术C#无积累,
那么将导致项目水平更大权重取决于空降主程、主程因故无法工作事其他语种程序员难以接手。
CTO因不能精通所有种类语言和解决方案,从倾向技术变为更多的倾向人事和产品策划方面管理、
要为每个项目单独配置和调试后台对接、美术格式、工具链等。

这个方案对于资金和人事实力雄厚、侧重管理而非技术、侧重运营而非策划、甚至侧重收购而非开发的大公司不成问题。
大公司同语种项目可能有不止两三个,能迅速地进行人员抽调、配置专门人力提供公用工具、甚至最差情况项目砍了算了。
以我司小公司实际情况,这个方案代价颇为沉重。


然后
将旧库完全手写成C#,旧库如出现修改,那么C#也同样要修改,用写代码常用的话就是出现了耦合。把一个我设计的类,聘用不同语种程序员重写,
因程序员本身的差异也会开销大量时间。重写者和之后的维护者也很可能不是一个人。
如之后公司另立项H5项目,那么一处修改将需要用三种语言各写一遍。


最后
制定的方案是游戏核心部分和基本类库从AS3经代码转换工具转变为C#,
C#+Unity部分负责提供运行库支持,即实现DisplayObject等AIR运行时必须类
在此方案下,
“底层算法”始终使用AS3开发维护,
每次修改重跑一次工具转换到C#就可以了。
对所有项目,素材、后台对接、编辑器、工具链可以使用相同的一套
关于DisplayObject等运行库,因为做好便不会修改,对每个非AIR解决方案这是一次性工作

说实在的,
身为一名小公司CTO,我无法放心把公司核心项目直接托付给对应程序员

能对所有项目底层技术进行把控,而不是干脆地专成管理位置,我认为这是公司目前长治久安的一个保证。
我司也好,业内也好,程序员离职、生病无可避免。
项目底层一定要有人负责,比起每个项目单独依赖别人,不如依赖我好了。



大道理就这么多,下次开始写实际的转换内容。



回复 支持 反对

使用道具 举报

签到天数: 2 天

 楼主| 发表于 2018-11-9 15:06:53 | 显示全部楼层
本帖最后由 general_clarke 于 2018-11-14 14:21 编辑

【一】

这个转换方案很大。我所知业内并没有成熟值得借鉴的方案,当然如果有我也没想拿来使用。随便能拿来用还没坑的方案,我们能用,别人也能,
成不了核心竞争力。

为了确认方案是否可行,首先将方案进行细化,有哪些工作要做,逐一确认可行性

从流程上
1,制定通用素材格式,这个比较简单,用PNG就好。
2,制作实例的AS代码
3,将AS3代码转换成C#
4,让这段C#在Unity下成功运行,效果和AS3内一致

从复杂程度上
1,转换trace("HelloWorld")
2,转换一个小球从屏幕左移动到屏幕右
3,转换文本框、声音和其他基本、必要的类
4,转换老项目框架和工具库,对其功能逐一进行尝试
5,转换实际项目业务代码
6,这个是扩展的,让转换成C#的代码支持热更。

总体来看思路清晰,工作量不少,不同步骤难度各异。

转换并不需要实现AIR运行时的所有类,一些类(比如Math)在C#也能比较简单找到对应
所以实际C#编写运行库所需的,只是编写
flash.display包
flash.event包
flash.text包
flash.media包
flash.system包
flash.utils包
其中的一部分常用类以及顶层类。

经过基本分析我认为这个方案是可行的,

那么,先订个小目标


var a:String = "HelloWorld";
trace(a);
转换成
string a = "HelloWorld";
System.Console.WriteLine(a);

简单语法是转换的基础,这个我们已实现功能,实际步骤比看上去的复杂,
下次写这个。

回复 支持 反对

使用道具 举报

签到天数: 188 天

[LV.6]高级闪侠

发表于 2018-11-9 16:15:39 | 显示全部楼层
关注。。

点评

因为此帖子是工作记录形式,可能更新时间达到数个月,完全不占楼不太可能,插楼不要紧请自便。  发表于 2018-11-9 17:37
尽量别占将军的楼,可以多多点评~~  发表于 2018-11-9 17:05
回复 支持 反对

使用道具 举报

签到天数: 2 天

 楼主| 发表于 2018-11-9 16:45:03 | 显示全部楼层
本帖最后由 general_clarke 于 2018-11-10 12:11 编辑

为了将
var a:String = "HelloWorld";
trace(a);
转换成
string a = "HelloWorld";
System.Console.WriteLine(a);
首先要让程序能读懂这句的单词和语法。

将上述代码当作字符串
使用for循环逐个charAt(i),制定规则断句
所谓断句的规则,
从0位置开始,
在当前位置读入一个字符,如果是英文,那么向后一直读到下个英数之外字符之前位置,根据内容分类成关键字或标识符。
当前位置读入的如果是数字,向后读到下个非数字的字符之前位置,读取到的内容作为数字
当前位置读入的如果是其他符号,向后读到下个空白区域或者英数之前位置,读取到的内容作为符号。
一些特例,比如0x开头的数字,或者写作英数的符号(is as in)因为是特例所以特殊判断。
再如"*"有时表示乘法,有时表示类型。
因为实际上特例颇多,这个字符串解析步骤我做了不少天才完成

之后得到了下面的数组。

[["关键字", var], ["空白", " "], ["标识符", "a"], ["符号",":"], ["标识符", "String"], ["空白", " "], ["符号", "="], ["空白", " "], ["字符串", "\"HelloWorld\""], ["符号", ";"]]
这样得到了as3原文每个“单词”的类型数组。

用数组表示“单词”不利于扩展,
设每个不能形成AS3Value但是有意义的”单词”为AS3Atom,根据单词的类型做AS3Atom的不同派生类
例如上面提到的["标识符", "a"],表示成new AS3AtomSymbol("a");
整个var a:String = "HelloWorld";被转换为
[new AS3AtomKey("var"), new AS3Space(" "), new AS3AtomSymbol("a"), new AS3AtomOper(":"), new AS3AtomSymbol("String"), new AS3AtomSpace(" "), new AS3AtomOper("="), new AS3AtomSpace(" "), new AS3AtomString("\"HelloWorld\""), new AS3AtomOper(";")]


同理获得到trace(a);的每个“单词”类型数组
有了单词,那么接着考虑的是如何来表示语法。





回复 支持 反对

使用道具 举报

签到天数: 2 天

 楼主| 发表于 2018-11-9 17:30:30 | 显示全部楼层
本帖最后由 general_clarke 于 2018-11-10 12:12 编辑

as3也好,其他语言也好。每句的语法是由关键字和运算符决定的。

例如关键字是if,那么语法是
if(【A】){【B】}
再如运算符是+=,那么语法是
【A】+=【B】


类似a = b,a-=3这样二元运算符决定的语句很多,决定先攻克这个语法
称其为AS3Value


一个普通的二元运算AS3Value有三个元素,即左元素,运算符和右元素,形如【A】【符号】【B】

其中的【A】和【B】可以是AS3Atom或其他AS3Value,
因此
令AS3Value和AS3Atom共同继承自最小单位AS3ElementBase。
令AS3Value的构造函数为public AS3Value(left:AS3ElementBase, oper:AS3AtomOper, right:AS3ElementBase)


举例:
a = 1+b-3*4;
根据运算符优先级会断句成如下形式,
(a = ((1+b)-(3*4)))每个括号中一定只有3个元素构成【A】【符号】【B】形式。(忽视空格和分号)
P.S.关于如何根据运算符优先级确定表达式计算顺序,可于网上搜索“前缀式”或“后缀式”来了解。


例子的
a = 1+b-3*4;
转换成单词数组为
[new AS3AtomSymbol("a"), new AS3AtomSpace(" "), new AS3AtomOper("="), new AS3AtomSpace(" "), new AS3AtomNumber("1"),new AS3AtomOper("+"),new AS3AtomSymbol("b"),new AS3AtomOper("-"),new AS3AtomNumber("3"),new AS3AtomOper("*"),new AS3AtomNumber("4"),new AS3AtomOper(";")]
根据运算符优先级断句后,变成
new AS3Value(new AS3AtomSymbol("a"), new AS3AtomOper("="), new AS3Value(new AS3Value(new AS3AtomNumber("1"), new AS3AtomOper("+"), new AS3AtomSymbol("b")), new AS3AtomOper("-"), new AS3Value(new AS3AtomNumber("3"), new AS3AtomOper("*"),new AS3AtomNumber("4"))));

写得清晰一点就是
[AS3Value] a
        [object AS3Atom<symbol @192>] a
        [object AS3Atom<oper> @194] =
        [AS3Value]
                [AS3Value] b
                        [object AS3Atom<number> @196] 1
                        [object AS3Atom<oper> @197] +
                        [object AS3Atom<symbol> @198] b
                [object AS3Atom<oper> @199] -
                [AS3Value]
                        [object AS3Atom<number> @200] 3
                        [object AS3Atom<oper> @201] *
                        [object AS3Atom<number> @202] 4



P.S.
@后的数字是Atom的生成顺序请忽视,下同
回复 支持 反对

使用道具 举报

签到天数: 2 天

 楼主| 发表于 2018-11-10 11:30:39 | 显示全部楼层
本帖最后由 general_clarke 于 2018-11-10 12:13 编辑

因为经过上述步骤,已经能根据as文件分析出所有的单词类型,也知道了简单的语法,
所以做了一个代码转换的副产品。
9ria的老坛友可能记得我发代码经常带着和论坛自带染色工具不同的颜色

package
{
        public class testClass extends Sprite
        {
                public var field:String;
                public function testClass():void{
                        var a:String = "HelloWorld";
                        trace(a);
                        var b:int = 1+2;
                        field = func1(a);
                }
                public function func(p:String):String{
                        return p;
                }
        }
}

经转换成
package {
        public class testClass extends Sprite
        {
                public var field:String;

                public function testClass ():void {
                        var a:String = "HelloWorld";
                        trace(a);
                        var b:int = 1 + 2;
                        field = func1(a);
                }//end of Function testClass

                public function func (p:String):String {
                        return p;
                }//end of Function func
        }
}





回复 支持 反对

使用道具 举报

签到天数: 2 天

 楼主| 发表于 2018-11-10 11:37:00 | 显示全部楼层
[ 本帖最后由 general_clarke 于 2018-11-10 12:00 编辑 ]\n\n此楼层禁用了Discuz!论坛编辑器代码。
楼上做的事情,
就是将var a:String = "HelloWorld";
转换成语法树
[AS3Var] a     
        [AS3Var] a            
                [object AS3Atom<key> @40] var
                [AS3Value] a
                        [object AS3Atom<symbol> @42] a
                        [object AS3Atom<oper> @43] :
                        [object AS3Atom<symbol> @44] String
                [object AS3Atom<oper> @46] =
                [object AS3Seg<string> @48]  "HelloWorld"

之后在语法树中递归地处理语法树每个节点,根据节点的不同类型前后插入Discuz!论坛编辑器代码,形成了
[color=6699cc]var[/color] a[color=000000]:[/color]String = [color=990000]"HelloWorld"[/color];
在不禁用论坛编辑器代码时即显示出代码染色
回复 支持 反对

使用道具 举报

签到天数: 2 天

 楼主| 发表于 2018-11-10 17:56:43 | 显示全部楼层
包括var语法、new,return,if,for,switch-case,do-while,
包头,类头,函数头,
匿名数组,匿名对象,匿名函数,

此工具能解析的语法足够支持一个项目的所有常用代码时,花费了一个半月时间。
回复 支持 反对

使用道具 举报

签到天数: 2 天

 楼主| 发表于 2018-11-12 11:53:04 | 显示全部楼层
本帖最后由 general_clarke 于 2018-11-14 14:21 编辑

【二】

因为使用adobe技术,我们的很多FLA文件需要使用JSFL处理。
编写JSFL使用JS,
一句
var a:int = 10
在JS中写作
var a = 10
即需要去掉类型。

那么之后尝试使用此工具完成这项任务。
难度并不是很大,只需要找出所有的var语句,输出时将var语句冒号后的内容去掉即可,
不到半天就写完了。

后来想到了其实
str = str.replace(/(var\s+[\w\)]+\s*)\:\w+/g,"$1");
就能解决问题,

这半天时间从结果上是做了白工。
从过程上,好歹是代码转换工具是真正地完成了从一门语言转换成另一门语言的过程。

好吧,虽然是转换,
AS3是JS的超集,这个转换太low了。

楼主做到这里的时候,cocos是热门的技术,而flash在被唱衰。
为公司长远发展保底,我们聘请了同时会用C和as3的程序员
希望编写对接库。

对接库实现最基本的flash数据结构,display、text、event、utils等重要包,
在代码转换成C语言后进行对接。
这不是重新编写一个AVM虚拟机,
例如,
AVM虚拟机会定义Number数据结构,运算经过复杂的判空容错,
但是我们转码不会,转码中Number会直接被转换成double或long,使用C语言自带运算。
所以虚拟机运行效率是C系语言的1/10以下,直接转码效率几乎等同于C系语言。

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐上一条 /2 下一条

快速回复 返回顶部 返回列表