2008年12月30日 星期二

好玩的物理俄羅斯方塊


好玩的物理俄羅斯方塊
跟一般的玩法不太一樣
要比賽的是看誰能把方塊推的最高
當推的越高, 平衡度就越差, 就很容易不小心就整個跨掉
目前奶小茶我的最高分是210。


也是一個很有趣的物理遊戲。
使用鍵盤的上、左、右鍵控製人物的移動
再搭配滑鼠來畫製路線讓人物行走,直到走到終點
滿有趣的

2008年12月29日 星期一

ActionScript3.0 記憶體釋放問題

大家好,我是奶綠茶
一個好的Flash作品, 除了要有美美的設計與酷炫的動態外
奶小茶我覺的更重要的應該是效能。
我們就以一個EnterFrame事件來說明好了。
在ActionScript2.0時, MovieClip的EnterFrame事件, 當該MovieClip被移除時
其事件也會自動消失。
但在ActionScript3.0, 把該MoviecClip移除, EnterFrame還是會在。
所以當你載入越多的swf檔時, 沒有把前一個swf事件都移除的話, 效能就會越來越差。
那要如何移除事件呢?
//偵聽
clip.addEventListener(事件類型:String , 偵聽者函式:Function)
//取消偵聽
clip.removeEventListener(事件類型:String , 偵聽者函式:Function);
那什麼時候要取消偵聽?
通常在移除可視物件時, 就要把所有的事件都取消掉, 這樣才不會一直佔住記憶體。
可視物件有個Event.REMOVE_FROM_STAGE可以加以利用
當物件被從stage移除時, 會廣播該事件。
當偵聽者聽到時, 就把所有有註冊的事件通通取消掉。

被載入的Loaded.swf
在建構函式時就偵聽Event.ENTER_FRAME事件。
package  {  
import flash.display.Sprite;
import flash.events.Event; 
public class Loaded extends Sprite{  
public function Loaded() {
this.addEventListener(Event.ENTER_FRAME, onEventEnterFrame);
}  
private function onEventEnterFrame(e:Event):void {
trace(e);
}  
} 
}
載入的主要SWF
package  {  
import com.bit101.components.PushButton;
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.net.URLRequest;
[SWF(width = "950", height = "500", frameRate = "41", backgroundColor = "#000000", pageTitle = "milkmidi.com")] 
public class Main extends Sprite{  
private var _ldr:Loader
public function Main() {
_ldr = new Loader();
_ldr.load(new URLRequest("Loaded.swf"));   
this.addChild(_ldr);
var _btn:PushButton = new PushButton(this, 0, 0, "unload", onClick);   
}  
private function onClick(e:MouseEvent):void{
_ldr.unload();
}  
} 
}
發怖成功後, 可以看到面版不斷的輸出文字,
按下按鈕 ,unload該swf, 還是看到面版不斷的輸出文字, 也就表示物件移除
不代表事件移除, 所以我們改寫一下Loaded.swf的程式碼。
package  {  
import flash.display.Sprite;
import flash.events.Event; 
public class Loaded extends Sprite{  
public function Loaded() {
this.addEventListener(Event.ADDED_TO_STAGE, onAdd2Stage);
//當可視物件被加入至場景後, 會發出的事件。
this.addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);   
//當可視物件被移除後至場景, 會發出的事件。
}   
private function onRemovedFromStage(e:Event):void {
//物件被移除, 所有有偵聽的事件也要手動取消掉。   
this.removeEventListener(Event.ADDED_TO_STAGE, onAdd2Stage);
this.removeEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
this.removeEventListener(Event.ENTER_FRAME, onEventEnterFrame);
}  
private function onAdd2Stage(e:Event):void {
this.addEventListener(Event.ENTER_FRAME, onEventEnterFrame);
}
private function onEventEnterFrame(e:Event):void {
trace(e);
}  
} 
}
這樣當物件被除掉後, 也可以一起把事件都取消掉

補充一下:
在google找了些相關資訊, 發現一種不正規的Hack方法
但真的能將記憶體給釋放:
import flash.net.LocalConnection;
import flash.system.System;
try{
new LocalConnection().connect("foo");
new LocalConnection().connect("foo");
}catch(error : Error){
} 
//透過try catch,讓Player的garbage collection強製他回收不用的記憶體
System.gc();
//強制執行記憶體回收程序

FlashAS3好書一推

最近在天龍買了一本flash ActionScript3殿堂之路
http://www.books.com.tw/exep/prod/booksfile.php?item=0010397926
是大陸的黑羽翔天所寫的
看完之後整個對ActionScript3大大了解呀
原來還有許多的小細結我沒注意到。
本書完全是程式碼和ActionScript3.0的架構說明
說明事件流, 可視物件等等的。
如果想徹底的搞懂Flash, 本書真的很值得推薦。
簡體版一本才230元台幣, 可以在天龍找到喔!

2008年12月28日 星期日

Flash10 FileSaveAndLoad

FlashPlayer10
FileReference新增了save的功能。
能直接產生一個實體的檔案讓使用者下載。
在這兒我們就來練習載入一張圖片,畫圖後,再重新另存成一張新的.jpg
Thumbnail - Click me


除了筆者的程式碼, 還需要下載JPGEncoder編碼類別。
可以在這兒下載。
http://code.google.com/p/as3corelib/downloads/list
還有bit101作者的組件。
http://milkmidi.blogspot.com/2008/12/as3.html
需要使用FlashCS4或是FlexSDK4才能發怖成功。


package
{
import com.bit101.components.PushButton;
//匯入bit101作者的組件包。
import com.adobe.images.JPGEncoder;
//匯入JPGEncoder編碼
import flash.display.*;
import flash.events.*;
import flash.geom.Rectangle;
import flash.text.*;
import flash.net.*;
import flash.utils.ByteArray;


[SWF(width="800", height="600", backgroundColor="#FFFFFF", framerate="30")]

public class ImageFileLoadAndSave extends Sprite
{
private var _file  :FileReference;  
private var _ldr  :Loader = new Loader();  

public function ImageFileLoadAndSave():void
{
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT; 
//設定stage屬性。

this.addChild(_ldr);
//將_ldr加入至目前的可視物件容器。
_ldr.y = 40;

var pub1:PushButton = new PushButton(this, 0, 0, "Load File", onFileLoad);
var pub2:PushButton = new PushButton(this, 100, 0, "Save File", onSave);   
//建立二個Button。

_file = new FileReference();
_file.addEventListener(Event.SELECT, onSelect);
//當檔案被選取時。
_file.addEventListener(Event.COMPLETE, onComplete);
//當檔案被成功載入時。
}

private function onFileLoad(e:Event):void{
_file.browse([new FileFilter("Images Formats (*.jpg,*.gif,*.png,*.swf)", "*.jpg;*.gif;*.png;*.swf", "JPEG;jp2_;GIFF;SWF")]);     
}

private function onSelect(e:Event):void {
_file.load();
//載入。
}

private function onComplete(e:Event):void{   
var _data:ByteArray = _file.data;    
_ldr.loadBytes(_data);        
}

private function onSave(e:Event):void {
var bmp:BitmapData = new BitmapData(400, 300, false);   
bmp.draw(this);
//使用BitmapData的draw方法, 繪製目前的物件。
var jpg:JPGEncoder = new JPGEncoder(80);
//建立JPGEncoder編碼類別。
var by:ByteArray = jpg.encode(bmp);   
//將BitmapData編碼成ByteArray格式。
try {
_file.save(by, _file.name.split(".")[0] + ".jpg");   
//使用FilReference類別的save方法
//將ByteArray存成實體的.jpg。
}catch (err:Error){
trace(err);
}

}
}
}


2008年12月26日 星期五

Hairtry.jp-髮型設計系統

一個線上合成的髮型設計系統
http://www.hairtry.jp/
跟我之前製作過百齡罈專案使用的是同一家的3D臉部辨示系統。
不過我一時找不到該系統公司, 如果有好事人事找到麻煩跟我說一下。


FlashDevelop3介紹

想把ActionScript3.0學好, 開發工具可是非常重要滴。
想要學好FLASH ActionScript, 一定要有一套好的開發工具
用Flash內建的編輯器嗎?, 非常的不smart, 而且在CS3版, autoformat還有一堆問題
FlashDevelop3是一套免費的小巧型程式碼編輯器,
擁有完善的程式碼提示, 也可直接將.as檔或是mxml檔發怖成.swf檔。
目前的版本為FlashDevelop3 RC1
選用flashdevelop的好處
1.自定類別,也可以有程式碼的提示(在FLASH裡只會提示內建的類別)
2.不用開啟FLASH,也可以將as或是mxml compiler成.swf(需要下載>flex SDK檔)。
3.軟體本身檔案小,開啟的速度很快。
完整功能介紹:
http://www.flashdevelop.org/wikidocs/index.php?title=Features:Completion
軟體下載:
http://www.flashdevelop.org/community/viewtopic.php?f=11&t=4041
安裝軟體前, 你的作業環境需要安裝過.net framework2.0以上版本

軟體介面:

安裝完FlashDevelop後, 還有二個動作。
1.設定類別包路徑, 這樣FlashDevelop才抓的到該類別的程式碼提示。
上方工具列的:Tools/global Classpaths

選擇ActionScript3
按下Add Classpath,新增路徑。
指定到資料夾即可。

哇, PV3D的類別程式碼提示,太讚了啦


2.設定Flex SDK檔, 才可以直接將as檔發怖成.swf格式
下載Flex SDK,可以到adobe的網站免費下載使用。
FlexSDK3
目前的版本為SDK3.2, 有三個版本可以載入, 我們選檔案最小的就可以Open Source Flex SDK
約24mb
下載完成解壓縮, 筆者放的路徑是D:\FlexSDK
選擇上方工具列Tools/Progrom settings
再選擇左方的AS3Context,右方即有個Flex SDK Location路徑可以設定
填入路徑即可。

3.新增一個專案
上方的工具列,project/new Project
選擇AS3,empty project

將你要發怖的AS檔跟其專案在置在一起
先在Project面版上,設定輸出的.swf名稱


選擇你要發怖的AS檔或是mxml檔,按下右鍵選擇always comile

按下ctrl+Entry,即可發怖成.swf
前提是你的.as檔一定要是繼承Sprite或是MovieClip才行


2008年12月25日 星期四

PV3D Control DAE Animation

找了好久,終於找到一篇很不錯的PV3D DAE動畫教學。
該作者還寫了一個DAEMC的類別, 就把DAE當成MovieClip來使用
http://pablobandin.wordpress.com/2008/12/06/control-dae-animation/
奶小茶試了一下, 支援最新版的PV3D, 正點呀
而且還有低面數的3D Model可以下載使用
http://www.tomtallian.com/

該作者是使用3D Max來製作
還有影片教學呀。

動態文字製作mask效果

動態文字如果直接使用時間軸來製作mask



在製作階段時雖然有效果, 但發怖時後動態文字會整個消失。
決解的方法有二個:
1.對該動態文字新增一個濾鏡效果, 然後把參數調成0, 這樣看起來就像是沒有濾鏡,
我們新增一個Blur。

發怖後態動文字即可使用時間軸來mask。
2.將動態文字包在一個MovieClip裡, 然後mask也轉成MoveiClip元件。
取好實體名稱, 筆者分別取名為txt_mc和mask_mc。
下程式碼:

這樣一樣可以有mask的效果


感謝Brian補充文章:
1. 所有遮罩與遮罩下的物件都要轉成MovieClip
2. 也都要勾選"Use runtime bitmap caching"
3. 接下來也需要用奶老師提到的script設定遮罩才會生效.
4. 需要注意的是, 多個物件不能共用一個遮罩物件. 如果有多個物件需要共用到同一個遮罩, 建議是把這多個物件再包在一個MovieClip裡.

後來發現有更快的方法:
1. 將動態文字包成一個MovieClip裡。
2. 點選被遮色的MovieClip,並在下方屬性面版勾選的"Use runtime bitmap caching"。

3. 畫個色塊, 直接使用時間軸來遮色。
3. 完成。


2008年12月24日 星期三

AS3 自定事件

ActionScript3.0事件機制非常的完善
透過偵聽函式即可以得知廣播者發出的事件。
我們希望發件事件時, 能一起把自定的參數也發送出去
這時候就要自定一個類別來繼承Event。
自定一個名為LoaderEvent的類別。
定義靜態常數字串。


package milkmidi.events{ 
import flash.events.Event; 
public class LoaderEvent extends Event  {  
public static const LOADER_COMPLETE :String = "loaderComplete";
public static const LOADER_PROGRESS :String = "loaderProgress";
public static const LOADER_ERROR :String = "loaderError";
public var percentage:Number = 0;  
public function LoaderEvent(p_type:String , p_percentage:Number = 0) {   
super( p_type );   
this.percentage = p_percentage;
}   
}
}

新增一個名為LoaderX類別繼承Loader
package milkmidi.display{  
import flash.display.Loader;  
import flash.events.Event; 
import flash.net.URLRequest;
import flash.system.LoaderContext;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent; 
import milkmidi.events.LoaderEvent;

public class LoaderX extends Loader   {       
public function LoaderX() { 
super();         
this.contentLoaderInfo.addEventListener(Event.COMPLETE, _innerOnComplete, false, 0, true);
this.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, _innerOnProgress, false, 0, true);
this.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, _innerOnIOError, false, 0, true);   
}    
override public function load(p_url:URLRequest, p_context:LoaderContext = null):void {   
throw new Error("EEEEEEERRRORROOROROR");
}
public function loadURL(p_url:String, p_context:LoaderContext = null):void  {     
super.load(new URLRequest(p_url), p_context);   
}   
private function _innerOnComplete(e:Event): void {     
this.dispatchEvent(new LoaderEvent(LoaderEvent.LOADER_COMPLETE));
//載入完成時, 發送自定的LoaderEvent.LOADER_COMPLETE事件。
}
private function _innerOnProgress(e:ProgressEvent):void{   
var percentage:int =  int(e.bytesLoaded / e.bytesTotal * 100);      
this.dispatchEvent(new LoaderEvent(LoaderEvent.LOADER_PROGRESS, percentage));   
//載入進行中, 發送自定的LoaderEvent.LOADER_PROGRESS事件。
//發發事件時, 也把參數percentage發送出去。
}
private function _innerOnIOError(e:IOErrorEvent):void{   
this.dispatchEvent(new LoaderEvent(LoaderEvent.LOADER_ERROR));
}  
}
}

測試:
package  {
import flash.display.Sprite; 
import milkmidi.display.LoaderX;
import milkmidi.events.LoaderEvent;
public class Demo extends Sprite{  
private var _ldr:LoaderX;
public function Demo() {
_ldr = new LoaderX();
_ldr.addEventListener(LoaderEvent.LOADER_COMPLETE, onLoaderComplete);
_ldr.addEventListener(LoaderEvent.LOADER_PROGRESS, onLoaderProgress);
//因為我們自定的LoaderX是繼承Loader, 擁有Loader類別所有的方法和屬性。
//同時我們擴充該類別, 讓他會發出LoaderEvent事件, 所以要改為偵聽LoaderEvent事件。
_ldr.loadURL("demo.jpg");
this.addChild(_ldr);
}

private function onLoaderComplete(e:LoaderEvent):void {
trace(e);
}

private function onLoaderProgress(e:LoaderEvent):void {
trace(e.percentage);
//接收到事件時, e物件會有percentage屬性。
//直接就是載入的百入比值。
}  
} 
}
建構一個LoaderX物件,來取代Loader
要偵聽Loader物件時
以前要寫
Loader實體.contentLoaderInfo.addEventListener(Event.COMPLETE,偵聽函式);
現在改成:
LoaderX實體.addEventListener(LoaderEvent.LOADER_COMPLETE,偵聽函式);
這樣就可以不需要再多打一個contentLoaderInfo
同時在偵聽事件時, 能再多接收參數。

SourceCodeDownload

線上版Photoshop

介紹幾個使用Flash製作的線上Photoshop
功能很完善
能開啟本機的檔案,編輯,存檔

http://www.sumo.fi/web


http://www.pixlr.com/app

2008年12月19日 星期五

Wonderfl Build Flash Online

一個滿有趣的網站
可以線上編輯程式碼
也可以修改別人寫好的code
http://wonderfl.kayac.com/
Mr.doob大師也在該網站有分享
有些效果還滿不錯滴。
如:
http://wonderfl.kayac.com/code/c97694f00c890c30a9b21edb080fdd62237ae03b
奶綠我分享的程式碼:

2008年12月9日 星期二

滿版定位

這一類的網站滿常見的
主要就是偵聽Stage的onResize事件
當事件發生時,就去改變物件的座標。



原始碼下載:AS2_AS3

2008年12月8日 星期一

MiniCarousel3D

小型的3DCarousel效果
奶老師寫了
AS2版本
AS3版本
Thumbnail - Click me

FLASH10版本
Thumbnail - Click me


共三個版本
當然FLASH10製作出來的效果最佳,因為有透視的效果
其他二個版本當然就只能使用scale來模擬。
都加入了Blur效果與影像變暗的效果。
原始碼:

解壓縮密碼:回覆文章就有密碼。
SourceCodeDownload

2008年12月5日 星期五

AS3音頻跳動效果

Flash ActionScript3.0後
已經可以抓取到mp3里的音頻資訊
這樣就可以製作出音頻跳動效果
使用的是SoundMixer類別。
Thumbnail - Click me

程式碼:
package 
{
import flash.display.Sprite;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.*;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundMixer;
import flash.media.SoundTransform;
import flash.net.URLRequest;
import flash.utils.ByteArray;
import flash.utils.Timer;
import flash.text.TextField;
import com.bit101.components.PushButton;

[SWF(width = "400", height = "300", frameRate = "31", backgroundColor = "#000000", pageTitle = "milkmidi")] 
public class MySoundDemo extends Sprite
{    
private var _bArray   :ByteArray = new ByteArray();      
private var _txt   :TextField = new TextField();  
private var _position  :Number = 0;
private var _sound   :Sound = new Sound();
private var _channel  :SoundChannel;    
public function MySoundDemo() {
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;  
//設定場景

_sound.addEventListener(Event.COMPLETE, completeHandler);          
//載入完成事件
_sound.addEventListener(ProgressEvent.PROGRESS, progressHandler);   
//載入進度
_sound.load(new URLRequest("MySound.mp3"));   
//載入mp3
_channel = _sound.play();
//播放sound
_channel.addEventListener(Event.SOUND_COMPLETE, soundCompleteHandler);
//偵聽歌曲是否播放完畢。


_txt.width = 200;
_txt.textColor = 0xFFFFFF;
//文字物件
this.addEventListener(Event.ENTER_FRAME, soundEnterFrame);
//EnterFrame事件
addChild(_txt); 

var playBtn:PushButton = new PushButton(this, 0, 20, "PLAY", onPlayClick);
var stopBtn:PushButton = new PushButton(this, 0, 40, "STOP", onStopClick);
var pauseBtn:PushButton = new PushButton(this, 0, 60, "PAUSE", onPauseClick);
//建立Button,使用的是bit101作者的類別。
}

private function onPauseClick(e:MouseEvent):void {   
_position = _channel.position;
//將現在播放的位置記錄在_position變數里。
_channel.stop();   
//停止。
}

private function onStopClick(e:MouseEvent):void {
_position = 0;   
_channel.stop();
}  
private function onPlayClick(e:MouseEvent):void {
_channel = _sound.play(_position);   
//從記錄的位置開始播放。
}
private function soundCompleteHandler(e:Event):void {
trace("soundCompleteHandler " + e);
//播放完畢,可以選擇再重新播放一次
}
private function soundEnterFrame(e:Event):void {

_txt.text = "positionTimer: " + int(_channel.position/1000) +" / " + int(_sound.length/1000);
//將播放的進度顯示在動態文字裡。
var n:Number = 0;
this.graphics.clear();
SoundMixer.computeSpectrum(_bArray, true, 0);
//SoundMixer可以得到目前.swf裡音頻的資訊。
for (var i:int = 0; i < 256; i = i + 16) {        
n = _bArray.readFloat();
//讀取ByteArray。
var num:Number = n * 360;
//將數值放大
this.graphics.lineStyle(10, 0x99FF00, 100, false, "noSacle", "none");
this.graphics.moveTo(50 + i, 200);
this.graphics.lineTo(50 + i, 200 - num / 5);
//繪圖。
}
}
private function completeHandler(e:Event):void  {
trace("completeHandler: " + e);
//載入完成
} 
private function progressHandler(e:ProgressEvent):void {
trace("progressHandler: " + e);
//載入中
}
}
}

超好用AS3小巧型組件_minimalcomps

對於經常要Coding的我們來說
有時候需要一個Button,但又懶的畫
可以參考bit-101作者所開發的組件minimalcomps
真的很好用又好看。
筆者的很多Demo也都是用使該組件。

http://www.bit-101.com/blog/?p=1126

PV3D_DoubleSidedCompositeMaterial

PV3D目前的版本沒有辦法有雙面不同的材質
還好有熱心的網友開發DoubleSidedCompositeMaterial
可以在這兒下載該類別:
http://www.nabble.com/backface-culling-td15978730.html
下載這個檔
http://www.nabble.com/attachment/16002163/0/DoubleSidedCompositeMaterial.as
支援的PV3D版本為Papervision3D_2.0_beta_1_src 2008.08.08版本。
Papervision3D_2.0_beta_1_src 2008.08.08
使用方法很簡單
當成CompositionMaterial使用就可以了。
Thumbnail - Click me


2008年12月4日 星期四

Away3D_OpenCube

最近又重新的把Away3D拿出來研究一下
發現新版的Away3D效果也很不錯
有些效果在PV3D上製作不出來
相對的,PV3D有些效果Away3D也製作不出來
像奶小茶我製作的這個Demo
PV3D Plane物件不能貼雙面不同的材質(有熱心的網友有寫DoubleSidedCompositeMaterial類別)
Away3D Plane直接就可以新增另一面的材質
Thumbnail - Click me

除了筆者的程式,還需要away3D2.2版的類別和Tweener類別
SourceCodeDownload