利用Socket解析HTTP头

这个问题我好奇了很久都没有结果,尝试搜索了大量类似“Flash解析HTTP头”、“AS3解析HTTP Header”、"Use AS3 to read/get HTTP Header"的关键词,大多数文章都是讲述如何构造HTTP头(我认为大概是为了用Flash模拟一些类似文件上传的请求来改善用户体验)。但是,利用Flash(AS)解析HTTP头,还真没想到啥好办法。

今天中午终于意识到,这个问题应该用Socket……这真的是一个“意识”的问题,太惭愧了!

当然,过程也稍微复杂一点,先要构造一个请求头,然后解析返回信息。不过可以将这些操作封装成一个类似load的public function出来,日后使用则如同URLLoader那样方便。

授人以鱼不如授人以渔,具体细节我就不赘述了,有兴趣的朋友们可以制作一个给我用,哈哈!

我认为一个优秀的ActionScript程序员应该具备的特殊技能

除了一些基本的OOP思想之外,我认为一个优秀的ActionScript程序员还应该具备:

  1. JSFL的编写能力 – 如果要你把300个类元件绑定好相应类文件输出,你难道会一个一个去改Linkage?
  2. 正则表达式的运用 – 无论是查代码还是实现功能,正则太重要!
  3. 支持宏的文本编辑器的使用 – ActionScript代码的整齐性非常好,这给宏提供了极大的用武之地
  4. 熟练使用Flash Authoring Tool – 有些事情用Shape画不如用Flash画。
  5. 知道Refactor – 命名规范不行的开发者更要善用Refactor
  6. 知道Reference – 知道你的类或者对象都在哪
  7. SVN – 一个人做项目用SVN也是有必要的。
  8. 较好与人沟通的能力 – AS3和AS1、2不同,讲究合作和谐,而不是单兵作战。

一个用于检测FPS和内存占用的小玩意

最近为CPU和内存占用的细节努力不少,自己也折腾出了一个检测器,用于实时检测FPS(实际上可以算是检测CPU)和内存占用情况。

使用方法,在application的Document Class(或者Application Class)上构建一个检测器实例(MonitorKit)并addChild即可,所含参数比较简单,不再一一赘述:

var monitor:MonitorKit = new MonitorKit(MonitorKit.MKMODE_T);
addChild(monitor);

效果图如下:

MonitorKit类如下:

package com.as3blog.utils{
  import flash.display.Sprite;
  import flash.display.Stage;
  import flash.events.Event;
  import flash.system.System;
  import flash.text.TextField;
  import flash.text.TextFieldAutoSize;
  import flash.text.TextFormat;
  import flash.utils.getTimer;
  
  public class MonitorKit extends Sprite{
    public static const MKMODE_T:String = "MKMODE_T";
    public static const MKMODE_B:String = "MKMODE_B";
    public static const MKMODE_L:String = "MKMODE_L";
    public static const MKMODE_R:String = "MKMODE_R";
    public static const MKMODE_TL:String = "MKMODE_TL";
    public static const MKMODE_TR:String = "MKMODE_TR";
    public static const MKMODE_BL:String = "MKMODE_BL";
    public static const MKMODE_BR:String = "MKMODE_BR";
    
    private static var stageInstance:Stage;
    
    private var lastTime:uint = getTimer();
    private var frames:Number = 0;
    private var monitorKitTextField:TextField;
    private var mode:String;
    private var textColor:uint;
    private var backgroundColor:uint;
    private var transparent:Boolean;
    public static var delay:Number = 0;
    public function MonitorKit(_mode:String = MKMODE_T,
        _transparent:Boolean = true,
        _textColor:uint=0xffffff,
        _backgroundColor:uint=0x000000) {
      mode = _mode;
      transparent = _transparent;
      textColor = _textColor;
      backgroundColor = _backgroundColor;
      // Initialize it when rendered on the stage.
      addEventListener(Event.ADDED_TO_STAGE, initMonitorHandler);
    }
    
    private function initMonitorHandler(event:Event):void {
      // Unregister the event handler
      removeEventListener(Event.ADDED_TO_STAGE, initMonitorHandler);
      stageInstance = this.stage;
      monitorKitTextField = new TextField();
      monitorKitTextField.selectable = false;
      monitorKitTextField.background = transparent;
      monitorKitTextField.textColor = textColor;
      monitorKitTextField.backgroundColor = backgroundColor;
      monitorKitTextField.autoSize = TextFieldAutoSize.LEFT;
      var format:TextFormat = new TextFormat();
      format.font = "Courier New";
      format.size = 15;
      monitorKitTextField.setTextFormat(format);
      monitorKitTextField.defaultTextFormat = format;
      monitorKitTextField.text = "[ Loading... ]";
      addChild(monitorKitTextField);
      stageInstance.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
    }
    
    public function enterFrameHandler(evt:Event):void {
      frames++;
      var currentTime:uint = getTimer();
      var deltaTime:uint = currentTime - lastTime;
      var fps:Number = frames / deltaTime * 1000;
      monitorKitTextField.text = "FPS: " + fps.toFixed(1);
      monitorKitTextField.appendText("\nMem: " + Number(System.totalMemory/1024/1024).toFixed(3)+"(M)");
      frames = 0;
      lastTime = currentTime;
      // Replace the monitor object
      switch (mode) {
        case MKMODE_T:
          monitorKitTextField.x = stageInstance.stageWidth / 2 - monitorKitTextField.width / 2;
          monitorKitTextField.y = 0;
          break;
        case MKMODE_B:
          monitorKitTextField.x = stageInstance.stageWidth / 2 - monitorKitTextField.width / 2;
          monitorKitTextField.y = stageInstance.stageHeight - monitorKitTextField.height;
          break;
        case MKMODE_L:
          monitorKitTextField.x = 0;
          monitorKitTextField.y = stageInstance.stageHeight / 2 - monitorKitTextField.height / 2;
          break;
        case MKMODE_R:
          monitorKitTextField.x = stageInstance.stageWidth - monitorKitTextField.width;
          monitorKitTextField.y = stageInstance.stageHeight / 2 - monitorKitTextField.height / 2;
          break;
        case MKMODE_TL:
          monitorKitTextField.x = 0;
          monitorKitTextField.y = 0;
          break;
        case MKMODE_TR:
          monitorKitTextField.x = stageInstance.stageWidth - monitorKitTextField.width;
          monitorKitTextField.y = 0;
          break;
        case MKMODE_BL:
          monitorKitTextField.x = 0;
          monitorKitTextField.y = stageInstance.stageHeight - monitorKitTextField.height;
          break;
        case MKMODE_BR:
          monitorKitTextField.x = stageInstance.stageWidth - monitorKitTextField.width;
          monitorKitTextField.y = stageInstance.stageHeight - monitorKitTextField.height;
          break;
        default:
        break;
      }
    }
  }
}

建立了一个关于AS3的Google Group,欢迎GMail用户加入

Google Group配合GMail可以十分方便、高效地讨论技术问题,为此,建立了一个AS3的邮件组交流技术问题。欢迎喜欢使用GMail的朋友们加入。

web地址:

http://groups.google.com/group/as3-discussion

邮件列表地址:

as3-discussion@googlegroups.com

需要加入者请联系这个邮箱,目前需要邀请才可以加入:

awflasher+urgent.as3@gmail.com

一些结论,松散地记录一下

  • FlashPlayer9内存管理方面比如FlashPlayer10好,尤其是在一些cacheAsBitmap属性为true的复杂图形进行一定幅度的缩放时(即重绘区域足够大)
  • FlashPlayer10在性能和内存管理方面均优于FlashPlayer9
  • 对于大量复杂的矢量动画,可以采用动态切换stage.quailty的做法让性能缓解(节约CPU占用)
  • 看到我这篇博客的读者,如果你认识我一段时间(并认为彼此性格相符)并有兴趣与我合作一个项目,可以看看这篇文章

闲话Flash中对小数坐标处理的问题

Update: 具体项目中,其实可以用扩展Sprite类并建立setter和getter来实现,不再赘述了。

一个头痛了几天的bug终于fixed……我真的是太迟钝了。

最近,遇到这样一个案例,需要以非常缓慢的速度移动某几个物体,而且,这些物体之间还会发生“无损弹性碰撞”(修正主义万恶的高中课本翻译的是“完全弹性碰撞”,我个人觉得Perfect Collision应该为“无损”更易理解吧?)

总之,这些物体的速度(即位移增量)可能灰常灰常小。小到什么程度呢?这么说吧,由于所有的值都是根据动量守恒定律和能量守恒定律(还记得这俩公式的同学你们可以去解放美帝国主义了)算出来的,因为难免出现某一个物体从某一个角度撞击另一个物体之后,两者中某一物体的某一方向(x或者y)上的速度被“中和”掉了。

刚才提到,在计算机语言中,速度即位移增量。ActoinScript的写法则是:

fuckCERNET.x += fuckCERNET.vx; //fuckCERNET is an instance of some dynamic class

当fuckCERNET.vx < 1/20时,Flash则不再渲染。这是根据FlashPlayer万恶的内部机制来实现的。根据我和一些美帝国主义的Flasher讨论,发现,FlashPlayer对物体x、y属性是有保护的:

Implementation
  public function get x():Number
  public function set x(value:Number):void

为什么要有这个保护呢,也不难理解:肯定是因为你直接让一个物体移动到0.001的位置上后计算机(FlashPlayer)不知道怎么去显示它:计算机是根据像素组成的,例如我们通常所说的1024×768:即便你的影片再高清再无码,你放到80×60的显示器上还是只能显示4800个点。

虽然“万恶”,但不得不承认FlashPlayer很聪明地回避了这样的问题,甚至,很优雅地通过一个setter来解决了问题,我们可以想象这个setter可能会是:

public function set x(value:Number):void {
  if (value < 0.05) value = 0;
  // blah .. blah
}

好的,知道这个之后,就好办了。每次速度改变(即碰撞的时候)做一次“最低值判断”:当速度标量(即不考虑方向)不为0(实际上这种情况很小)但小于0.05时,让速度等于0.05就好,可以用我写的这个函数来修正:

private function fixDecimalFractionPosition(value:Number):Number {
  if (Math.abs(value) < .05) {
    return (value > 0) ? .05 : -.05;
  }
  return value;
}

什么时候该用cacheAsBitmap,什么时候不该用

根据官方的说明,结合我自己的经验,分享一下:

该用cacheAsBitmap的时候:

  1. 在一个复杂的矢量化背景图片上存在大量动画;
  2. 滚动文本区域;
  3. 基于窗口的应用(你经常会拖拽整块区域)
  4. 透明遮罩(必须强制使用,否则失效)

不应该用cacheAsBitmap的时候:

  1. 不要滥用,cacheAsBitamp十分消耗内存,一块250×250像素的矩形进行cache之后可能占掉250kb的内存!
  2. 目标元素缩放的时候不要使用。
  3. 目标元素本身最好是静态的,或者不要经常发生翻转、缩放这样的动画
  4. 不要把矢量图和cache的位图一起混用。

Flex Builder编译错误An internal build error has occurred的解决方法

在Flex Builder调试ActoinScript项目时,偶尔会出现这种奇怪错误。原因主要是快速编译造成的:

Severity and Description    Path    Resource    Location    Creation Time    Id
An internal build error has occurred. Right-click for more information.        ****** Unknown

解决方法很简单,按如下步骤:

Help > Product Details. 点击 Configuration Details 按钮, 点击 View Error Log 按钮.

一般地,我们会找到这样的错误:

java.io.FileNotFoundException: D:\projects\google\MyProject.swf (The process cannot access the file because it is being used by another process)

at java.io.FileOutputStream.open(Native Method)
at java.io.FileOutputStream.<init>(Unknown Source)
at java.io.FileOutputStream.<init>(Unknown Source)
at com.adobe.flexbuilder.multisdk.compiler.internal.ASApplicationBuilder$MyBuilder.mybuild(ASApplicationBuilder.java:282)
at com.adobe.flexbuilder.multisdk.compiler.internal.ASApplicationBuilder.build(ASApplicationBuilder.java:122)
at com.adobe.flexbuilder.multisdk.compiler.internal.ASBuilder.build(ASBuilder.java:139)
at com.adobe.flexbuilder.multisdk.compiler.internal.ASItemBuilder.build(ASItemBuilder.java:73)
at com.adobe.flexbuilder.project.compiler.internal.FlexProjectBuilder.buildItem(Unknown Source)
at com.adobe.flexbuilder.project.compiler.internal.FlexProjectBuilder.build(Unknown Source)
at com.adobe.flexbuilder.project.compiler.internal.FlexIncrementalBuilder.build(Unknown Source)
at org.eclipse.core.internal.events.BuildManager$2.run(BuildManager.java:624)
at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:37)
at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:166)
at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:197)
at org.eclipse.core.internal.events.BuildManager$1.run(BuildManager.java:246)
at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:37)
at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:249)
at org.eclipse.core.internal.events.BuildManager.basicBuildLoop(BuildManager.java:302)
at org.eclipse.core.internal.events.BuildManager.build(BuildManager.java:334)
at org.eclipse.core.internal.events.AutoBuildJob.doBuild(AutoBuildJob.java:137)
at org.eclipse.core.internal.events.AutoBuildJob.run(AutoBuildJob.java:235)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)

原因就是表黑的那个文件被FlashPlayer.exe进程打开但没有关闭,因此Flex编译好的新文件无法覆盖这个文件。解决方法非常容易,打开Taskmgr,找到FlashPlayer.exe干掉就好了:)

Focus on ActionScript 3