2011年11月29日 星期二

[AS3] 寶石方塊的實作

寶石方塊~
一個算是基本中的基本的東西~
我是拿來練習Vector的部分~
用這個練習 Vector得到了很多的部分~
例如 一些檢驗的部分~ 非常的嚴謹~
Vector 如果超出所引範圍會報錯~
但是 array 不會~
Vector 就算是有限定了長度 如果不是設定固定~
也是可以利用 push去增加的
Vetor的排序較快! Array慢很多~

基本上這是一個很堅單的東東~
所以我就沒太多講解了~
如果有高手願意提供更好的寫法我也願意學習~
話說 Vector版的寶石方塊~
比我用 array的還慢~
理論上應該可以寫的比 array版的快~不過我是寫不出來了!
下面是我的原始碼!

vo 的部分 是地板的類別 目的是讓 vector可以使用


package vo
{
import flash.display.MovieClip;

public class jwFloor extends Object
{
public var mc:MovieClip;
public var type:int = 1;

public function jwFloor(
_mc:MovieClip,
_type:int = 1
)
{
super();
mc = _mc;
type = _type;
}
}
}



gameEvent 這個是放這遊戲傳出的動作 基本上有兩個 消去地板時傳出的 和結束遊戲傳出的

這個是如果整個遊戲中 沒有任何兩個方塊互換 可以消去時會傳出這個!

package gameEvent
{
import flash.events.Event;

public class gameOverEvent extends Event
{
public static const GAME_OVER:String = 'gameOver';

public function gameOverEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
}
}


這個是每次消去方塊時會傳出

package gameEvent
{
import flash.events.Event;

public class HitCountEvent extends Event
{
public static const HIT_COUNT_EVENT:String = 'gameHitCountEvent';

public var hit:int  = 0;        //總共有幾組方塊 在這一次操作中消去
public var countFloorMax:int = 0;// 這一次最大消去數量
public var totalFloor:int = 0; // 總共消去的地板數量

public function HitCountEvent(type:String,
hit:int = 0,
countFloorMax:int = 0,
totalFloor:int = 0,
bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
this.hit = hit;
this.countFloorMax = countFloorMax;
this.totalFloor = totalFloor;
}
}
}



下面這個是 整個遊戲的主體!

package
{
import caurina.transitions.Tweener;

import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;

import gameEvent.HitCountEvent;
import gameEvent.gameOverEvent;

import vo.jwFloor;

public class bejeweledGame extends Sprite
{
private var horNum:int = 10;
private var verNum:int = 10;
private var jwMap:Vector.<Vector.<jwFloor>>;
private var floorClasVec:Vector.<Class>;
private var selectMC:Sprite;
private var moveFlag:Boolean = false;
private var countHit:int = 0;
private var countFloor:int = 0;
private var totalFloor:int = 0;
public var hitPoint1:Point = new Point(-1,-1);
public var hitPoint2:Point = new Point(-1,-1);
//
private const moveFloorTime:Number = 0.3; // 兩塊地板移動使用的時間!
private const actionDelay:Number   = 0.1; // 動作結束後的延遲時間!
private const clearFloorTime:Number = 0.5;// 清理地板時間


public function bejeweledGame(_fcv:Vector.<Class>,
 _horNum:int=10,
 _verNum:int=10)
{
super();
this.addEventListener(Event.ADDED_TO_STAGE, onInitFun);
floorClasVec = _fcv;
horNum = _horNum;
verNum = _verNum;
countHit = 0;
countFloor = 0;
totalFloor = 0;
}

private function onInitFun(e:Event):void
{
this.removeEventListener(Event.ADDED_TO_STAGE, onInitFun);
jwMap = new Vector.<Vector.<jwFloor>>(verNum);
for(var i:int=0;i<verNum;i++)
{
var tempV:Vector.<jwFloor> = new Vector.<jwFloor>(horNum);
jwMap[i]= tempV;
for(var j:int=0;j<horNum;j++)
{
do{
var tempRn:int = Math.random()*floorClasVec.length;
var cla:Class  = floorClasVec[tempRn];
jwMap[i][j] = new jwFloor(new cla() as MovieClip, tempRn);
}while(hk(j,i)>2||vk(j,i)>2)
this.addChild(jwMap[i][j].mc);
jwMap[i][j].mc.x = j*jwMap[i][j].mc.width;
jwMap[i][j].mc.y = i*jwMap[i][j].mc.height;
jwMap[i][j].mc.dx = j;
jwMap[i][j].mc.dy = i;
}
}
selectMC = new Sprite();
selectMC.graphics.lineStyle(3,0xff0000,1);
selectMC.graphics.drawRect(0,0,jwMap[0][0].mc.width, jwMap[0][0].mc.height);
selectMC.mouseEnabled  = false;
selectMC.mouseChildren = false;
selectMC.visible = false;
this.addChild(selectMC);
this.addEventListener(MouseEvent.CLICK,  onClickFun);
}
// 點擊檢測
private function onClickFun(e:MouseEvent):void
{
var mc:MovieClip = e.target as MovieClip;
if(moveFlag) return;
if(!mc)return;
if(mc.dx == undefined){
mc = mc.parent as MovieClip;
}
if(mc.dx == undefined) return;
var x:int = mc.dx;
var y:int = mc.dy;
var sx:int = int(selectMC.x / mc.width);
var sy:int = int(selectMC.y / mc.height);
if((((x==sx+1||x==sx-1)&&y==sy)||
   ((y==sy+1||y==sy-1)&&x==sx)))
{
switchFloor( x, y, sx, sy);
if(hk(x,y)>2 ||
  vk(x,y)>2 ||
  hk(sx,sy)>2 ||
  vk(sx,sy)>2)
{
selectMC.x = -10;
selectMC.y = -10;
selectMC.visible = false;
Tweener.addTween(selectMC, {alpha:1,
time:moveFloorTime+actionDelay,
onComplete:SwitchMoveEndFun,
onCompleteParams:[sy>y?sy:y]});
return;
}else{
switchFloor( x, y, sx, sy);
}
}
selectMC.x = mc.x;
selectMC.y = mc.y;
selectMC.visible = true;
if(!getHit()) this.dispatchEvent(new gameOverEvent(gameOverEvent.GAME_OVER));
return;
}
//
private function SwitchMoveEndFun(maxY:int):void
{
clearFloor(maxY);
}
//
private function clearFloor(MaxY:int):void
{
var typeNum:int = -1;
var cont:int = 1;
var flagF:Boolean = false;
for(var i:int=0;i<this.verNum;i++)
{
typeNum = -1;
cont = 1;
for(var j:int=0;j<horNum;j++)
{
if(jwMap[i][j].type == typeNum)
{
cont++;
}else{
if(cont >= 3) flagF = clearHorFloor(j, i, cont);
cont = 1;
typeNum = jwMap[i][j].type;
}
}
if(cont >= 3) flagF = clearHorFloor(j, i , cont);
}
if(flagF){
Tweener.addTween(selectMC, {alpha:1, time:this.clearFloorTime+this.actionDelay, onComplete:HorMoveEndFun});
}else{
clearFloor2();
}
}
// 橫向清除動畫結束!
private function HorMoveEndFun():void
{
clearFloor2();
}
//
private function clearFloor2():void
{
var typeNum:int = -1;
var cont:int = 1;
var flagF:Boolean = false;
for(var j:int = 0;j<horNum;j++)
{
typeNum = -1;
cont = 1;
for(var i:int=0;i<verNum;i++)
{
if(jwMap[i][j])
{
if(jwMap[i][j].type == typeNum)
{
cont++;
}else{
if(cont >= 3) flagF = clearHVerFloor(j, i , cont);
cont = 1;
typeNum = jwMap[i][j].type;
}
}else{
if(cont >= 3) flagF = clearHVerFloor( j, i , cont);
cont = 1;
typeNum = -1;
}
}
if(cont >= 3) flagF = clearHVerFloor(j, i, cont);
}
//
if(flagF){
Tweener.addTween(selectMC, {alpha:1, time:this.clearFloorTime+this.actionDelay, onComplete:VerMoveEndFun});
}else{
clearFloor3();
}
}
//
private function VerMoveEndFun():void
{
clearFloor3();
}
//
private function clearFloor3():void
{
var typeNum:int = -1;
var cont:int = 1;
var flagF:Boolean = false;
// 垂直落下
var tempFloor:Vector.<jwFloor>;
for(var j:int=0;j<this.horNum;j++)
{
tempFloor = new Vector.<jwFloor>();
for(var i:int=0;i<this.verNum;i++) if(jwMap[i][j]) tempFloor.push(jwMap[i][j]);
for(i=verNum-1;i>=0;i--)
{
if(tempFloor.length>0){
jwMap[i][j] = tempFloor.pop();
}else{
var tempRn:int = Math.random()*floorClasVec.length;
var cla:Class  = floorClasVec[tempRn];
jwMap[i][j] = new jwFloor(new cla() as MovieClip, tempRn);
this.addChild(jwMap[i][j].mc);
jwMap[i][j].mc.x = j*jwMap[i][j].mc.width;
jwMap[i][j].mc.y = 0 - (jwMap[i][j].mc.height*(this.verNum-i));
flagF = true;
}
fixFloor( j, i);
}
}
if(!flagF){
trace("連擊! " + countHit + " Hit. 一共消除: " +  totalFloor + " 消除最大長度: " + countFloor);
moveFlag   = false;
this.dispatchEvent(
new HitCountEvent(HitCountEvent.HIT_COUNT_EVENT,
countHit,countFloor,totalFloor));
countHit   = 0;
totalFloor = 0;
countFloor = 0;
}else{
Tweener.addTween(selectMC,
{x:selectMC.x,
time:this.moveFloorTime+this.actionDelay,
onComplete:clearFloor,
onCompleteParams:[verNum]});
}
}
// 橫向清除 FLOOR
private function clearHorFloor(  x:int, y:int, long:int):Boolean
{
for(var i:int=1;i<=long;i++)
{
if(jwMap[y][(x-i)] || jwMap[y][(x-i)] != null)
{
//this.removeChild(jwMap[y][(x-i)].mc);
Tweener.addTween(jwMap[y][(x-i)].mc, {alpha:0, time:clearFloorTime});
jwMap[y][(x-i)] = null;
moveFlag = true;
}
}
countHit++;
totalFloor+=long;
if(long > countFloor) countFloor = long;
return true;
}
// 垂直清除FLOOR
private function clearHVerFloor( x:int, y:int, long:int):Boolean
{
for(var i:int=1;i<=long;i++)
{
if(jwMap[(y-i)][(x)] || jwMap[y-i][(x)] != null)
{
//this.removeChild(jwMap[(y-i)][(x)].mc);
Tweener.addTween(jwMap[(y-i)][(x)].mc, {alpha:0, time:clearFloorTime});
jwMap[(y-i)][(x)] = null;
moveFlag = true;
}
}
countHit++;
totalFloor+=long;
if(long > countFloor) countFloor = long;
return true;
}
// 兩個互換!
private function switchFloor( x1:int, y1:int,
 x2:int, y2:int, testMode:Boolean = false):void
{
var tempFloor:jwFloor = jwMap[y1][x1];
jwMap[y1][x1] = jwMap[y2][x2];
jwMap[y2][x2] = tempFloor;
fixFloor(x1,y1, testMode);
fixFloor(x2,y2, testMode);
}
//
private function fixFloor(x:int,y:int, testMode:Boolean = false):void
{
if(jwMap[y][x].mc){
jwMap[y][x].mc.dx = x;
jwMap[y][x].mc.dy = y;
if(testMode){
jwMap[(y)][(x)].mc.x = x*jwMap[y][x].mc.width;
jwMap[(y)][(x)].mc.y = y*jwMap[y][x].mc.height;
}else{
Tweener.addTween(jwMap[(y)][(x)].mc, {
x:x*jwMap[y][x].mc.width,
y:y*jwMap[y][x].mc.height,
time:moveFloorTime});
}
// jwMap[y][x].mc.x  = x*jwMap[y][x].mc.width;
// jwMap[y][x].mc.y  = y*jwMap[y][x].mc.height;
}
}
// 垂直檢查
private function hk(x:int, y:int):int
{
var nowCoun:int = 1;
var tempY:int = y;
var type:int = jwMap[y][x].type;
while(twoPointCheck2(type, x, tempY-1))
{
tempY--;
nowCoun++;
}
tempY = y;
while(twoPointCheck2(type, x, tempY+1))
{
tempY++;
nowCoun++;
}
return nowCoun;
}
// 水平檢查
private function vk(x:int, y:int):int
{
var nowCoun:int = 1;
var tempX:int = x;
var type:int = jwMap[y][x].type;
while(twoPointCheck2(type,tempX-1,y))
{
tempX--;
nowCoun++;
}
tempX = x;
while(twoPointCheck2(type, tempX+1,y))
{
tempX++;
nowCoun++;
}
return nowCoun;
}
// 兩個點的 type 是否一樣!!
private function twoPointCheck2(typeNum:int, x:int, y:int):Boolean
{
if(x < 0 || y < 0) return false;
if(x >= horNum || y >= verNum) return false;
if(jwMap[y] == null)    return false;
if(jwMap[y][x] == null) return false;
return typeNum == jwMap[y][x].type;
}
// 提示
public function getHit():Boolean
{
for(var i:int=0;i<verNum-1;i++)
{
for(var j:int= 0;j<horNum-1;j++)
{
switchFloor(j, i , j, i+1,true);
if( hk(j,i)>2 ||
vk(j,i)>2 ||
hk(j,i+1)>2 ||
vk(j,i+1)>2)
{
trace("(" +(j+1) + "," +(i+1)+")->" + "("+(j+1)+","+(i+2)+")");
switchFloor(j, i , j, i+1,true);
hitPoint1 = new Point(j+1,i+1);
hitPoint2 = new Point(j+1,i+2);
return true;
break;

}
switchFloor(j, i , j, i+1,true);
//
switchFloor(j, i , j+1, i,true);
if( hk(j,i)>2 ||
vk(j,i)>2 ||
hk(j+1,i)>2 ||
vk(j+1,i)>2)
{
trace("(" +(j+1) + "," +(i+1)+")->" + "("+(j+2)+","+(i+1)+")");
switchFloor(j, i , j+1, i,true);
hitPoint1 = new Point(j+1,i+1);
hitPoint2 = new Point(j+2,i+1);
return true;
break;
}
switchFloor(j, i , j+1, i,true);
}
}
hitPoint1 = new Point(-1,-1);
hitPoint2 = new Point(-1,-1);
return false;
}
// 清除全部!
public function clearAll():void
{
for(var i:int=0;i<verNum-1;i++)
{
for(var j:int= 0;j<horNum-1;j++)
{
if(jwMap[i][j])
{
this.addChild(jwMap[i][j].mc);
}
jwMap[i][j] = null;
}
jwMap[i] = null;
}
var len:int = floorClasVec.length;
for(i=0;i<len;i++)
{
floorClasVec.pop();
}
floorClasVec = null;
this.removeChild(selectMC);
selectMC = null;
countHit = 0;
this.removeEventListener(MouseEvent.CLICK,  onClickFun);
}

}
}

//
這整個是我的寶石方塊的程式碼~
有用到 tweener的類別~
其中一開始傳入的 _fcv 是存放本次有多少種不同的地板!
//
只有主體的SWF
主體的程式碼(我沒打包我的函數庫!)
有開始結束的版本!

2011年11月28日 星期一

[AS3] 一個超簡單的跑螺旋的方式

很久很久以前~
我自己寫的第一個特效就是跑螺旋!
超興奮的~
看到後來被人改成 瓢蟲 的時候~
我也是超興奮的~~
 不過現在看看~
我好像從那個時候起就沒成長過~~
不過來介紹一下~


package
{
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;

public class bejeweledAS extends Sprite
{
private var box:MovieClip; // 用來跑的物體!
private var ra:Number;     // 角度
private var r:int = 100;   // 長度
//
public function bejeweledAS()
{
box = new box07(); //我在引出的 MovieClip 的類別~
box.width  = 10;
box.height = 10;
this.addChild(box);
ra = 0;
r  = 10;
this.addEventListener(Event.ENTER_FRAME, onEnterFrameFun);
}
//
private function onEnterFrameFun(e:Event):void
{
box.x = r * Math.cos(ra*Math.PI/180) + 100;
box.y = r * Math.sin(ra*Math.PI/180) + 100;
ra += 10;
r  += 0.1;
}
}
}
一個最簡單的跑螺旋的方式~
改變一下角度是遞增遞減~
可以改變旋轉的方向~
改變一下~長度
會是轉入 或 是 轉出

===============================
剛剛學到一招~
使用 point的方法去處理~
據了解也是可以做到螺旋狀 !
Point.polar(r, ra*Math.PI/180);

詳細的可以看這個
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/geom/Point.html

然後我對下面兩個Function 作 unittest


public function test1():void
{
var r:int = 100;
for(var ra:int=0;ra<360;ra++)
{
r * Math.cos(ra*Math.PI/180) + 100;
r * Math.sin(ra*Math.PI/180) + 100;
}
}
public function test2():void
{
var r:int = 100;
var pi:Point;
for(var ra:int=0;ra<360;ra++)
{
Point.polar(r, ra*Math.PI/180);
}
}
結果讓我意外!

Math函數執行100次 消耗的時間為15毫秒 消耗 16384 記憶體 平均每次時間為 0.15毫秒
Point函數執行100次 消耗的時間為40毫秒 消耗 69632 記憶體 平均每次時間為 0.4毫秒
好像中間進行 GC 了

Math函數執行1000次 消耗的時間為163毫秒 消耗 16384 記憶體 平均每次時間為 0.163毫秒
Point函數執行1000次 消耗的時間為351毫秒 消耗 -40960 記憶體 平均每次時間為 0.351毫秒

基本上~使用三角函數計算的結果比用 Point.polar 快一截!
大家就看自己喜歡用啥就用啥瞜!

2011年11月27日 星期日

[AS3]ZendAMF + FLASH Builder 4.5 的測試+心得


恩~學一些新東西~
因為看某論壇說到 AMFPHP更新速度慢了!
裡面核心的人物 去開發 zendAMF了~
而且zend有ADOBE的幫助!
還有速度方面會比AMFPHP快!
所以我就想試看看 zendAMF的部分!
下面是我這次測試的整個的部分和遇上的問題!

先講一下我的系統
OS  WIN7
Apache 2.2.8
PHP 5.2.6
Zend AMF 1.11.11 (我本篇測試是使用傳說中的光棍板!)
FLASH Builder 4.5 (是使用官方下載的 4.5 的原生SDK )
基本上~應該相關的就這幾個!

1. 先拿到檔案 
zendAMF
http://framework.zend.com/download/amf

Appser(我是灌AppServ 2.5.10)
http://www.appservnetwork.com/?appserv

FB
http://www.adobe.com/downloads/

這邊我測過SDK 4.5.1 官網直接下載板 OK
還有置換過 AIR為 3.1版本的 4.5.1 都能順利執行本次測試!
不過為了通用起見~就用原本 4.5.0的SDK作講解

2. 安裝 zendAMF
步驟很簡單~解壓縮到你的 wwwRoot下~
以我的來說是在
C:\AppServ\www
以用光棍板來說解壓後是叫
ZendAMF-1.11.11

C:\AppServ\www\ZendAMF-1.11.11
我是覺得他的名稱太長所以我改成 zendAmf
然後在你的 zendAmf下建立一個PHP
getway.php (是參考 http://blog.corausir.org/programing/ausir-823 寫出來的 )


<?php
ini_set("display_errors", "On");
define ('P_S', PATH_SEPARATOR); //設定P_S是分隔符號;
set_include_path('.' .P_S .'library' .P_S . get_include_path()); // 設定include路徑
require_once 'library/Zend/Amf/Server.php'; //引入 AMF SERVER 類別
$server = new Zend_Amf_Server(); //建立 zendAmf的實體!
$server->addDirectory(dirname(__FILE__).'/services/'); //將整個資料夾都納入 SERVER 內
$result = $server->handle();
echo $result;
?>

先測試一下getway.php 是不是只輸出
Zend Amf Endpoint
如果是的話~那就是正確安裝了~
======如果有錯請看==========
如果不是就 看錯誤除錯吧~
話說我一開始getway.php 是沒有 define 和 set_include_path會報一堆錯~
然後我是傻傻的一個一個PHP去除錯~
基本上都是 require_once 找不到檔案!
後來我除到手痠~就COPY了一份 zend的到zendAmf的目錄下!
可以正常執行 但這個方法太笨! 
後來查一查~發現這個寫法~蠻不錯的 建議大家一定要用 set_include_path
其實整個zendAmf只有用到 library下的東西~
其他的我稍微看過了一下是測試和DOC基本上還是有幫助的!
所以我建議也是裝了吧!


3. 當然是 helloworld
先來 AS 版的!
先用 fb建立一個 as project (因為這個比簡單~設定的也少! 而且這個OK 基本上FLEX版的才會OK)

package
{
import flash.display.Sprite;
import flash.events.NetStatusEvent;
import flash.net.NetConnection;
import flash.net.ObjectEncoding;
import flash.net.Responder;

public class testZendAmfAS extends Sprite
{
public function testZendAmfAS()
{
var nc:NetConnection = new NetConnection();
NetConnection.defaultObjectEncoding = ObjectEncoding.AMF3; //設定傳輸的方式!
nc.connect('http://localhost/zendAmf/gateway.php'); //你的getway.php的路徑! 
var res:Responder = new Responder(onResultFun, onError);
nc.call("helloWorld.sayHelloWorld",res); 
   // 使用 Remote 方式連結 helloWorld 呼叫下面的 sayHelloWorld函數 傳回給 res   
}
private function onResultFun(e:Object):void 
{
trace(e + " Result!");
}
private function onError(err:Object):void 
{
for (var i:String in err) { 
trace(err[i] + ' ' + i + ' Error'); 
}
}
}
}

然後是 PHP的部分~
剛剛還記得
$server->addDirectory(dirname(__FILE__).'/services/');
C:\AppServ\www\zendAmf\services
下的PHP都會被引用近ZENDAMF裡可以供呼叫!
這樣就像是我用慣的AMFPHP的方式! 


基本上我拿了一些簡單的AMFPHP我寫的services 是都可以直接套用
不過拿一個最近案子的services 因為比較複雜~雖然沒錯! 但是整個不能運行!
現在就來一個簡單的 PHP



<?php
class helloWorld {
public  function sayHelloWorld(){
return "zendAmf is Running! Say Hello World!";
}
}
?>
這個PHP是放在  C:\AppServ\www\zendAmf\services 下喔!
雖然有看到說可以放子目錄的方式! 
但是我試過都不成功!
有心的人可以自己試看看!

基本上~
應該會看到
zendAmf is Running! Say Hello World!
的output在輸出面板!
到此為止你的 FLASH 和 zendAmf 已經正常得運行和聯動了!

接下來來一些比較高端的部分~
使用 flex的MXML去聯結 zendAmf的部分!
PHP的部分是一樣的
所以我就只講 FLEX的部分
一開始建一個 flex project
記得要按 next去設
web root 和 root url
以我的來說
web root : C:\AppServ\www
root url  : http://localhost/


然後是寫 services-config.xml 放在src下喔!
這個很重要!
要注意的點有幾個!


<?xml version="1.0" encoding="UTF-8"?>
<services-config>
<services>
<service id="sabreamf-flashremoting-service" class="flex.messaging.services.RemotingService"
messageTypes="flex.messaging.messages.RemotingMessage">
<destination id="zendAmf">
<channels>
<channel ref="my-amfphp" />
</channels>
<properties>
<source>*</source>
</properties>
</destination>
</service>
</services>
<channels>
<channel-definition id="my-amfphp" class="mx.messaging.channels.AMFChannel">
<endpoint uri="http://localhost/zendAmf/gateway.php" class="flex.messaging.endpoints.AMFEndpoint"  ></endpoint>
</channel-definition>
</channels>
</services-config>


endpoint uri="http://localhost/zendAmf/gateway.php"
這個很重要! 不要設錯了!
destination id="zendAmf" 這個也很重要~後面設定MXML會用到~
剩下的請自己去查巴!
對了~記得對你的 project按右鍵!
properties->flex compiler
記的多一行
-services "services-config.xml"
這樣才算設定完成!


然後是重頭戲! MXML的部分!



<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
  xmlns:s="library://ns.adobe.com/flex/spark"
  xmlns:mx="library://ns.adobe.com/flex/mx"
  creationComplete="init();"
  minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
import mx.rpc.events.FaultEvent;
import mx.rpc.events.InvokeEvent;
import mx.rpc.events.ResultEvent;

private function init():void{
amf.addEventListener(FaultEvent.FAULT,   onFaultFun); //如果傳回錯誤的監聽
amf.addEventListener(InvokeEvent.INVOKE, onInvokeFun);//如果傳出指令的監聽 理論上可以不設! 不過要了解所有傳出的動作可以從這裡做!
amf.addEventListener(ResultEvent.RESULT, onResultFun);//除理傳回值的部分! 雖然這三個都可以透過 MXML去設!
amf.sayHelloWorld(); //這個就是呼叫 HelloWorld函數的部分!
}
private function onFaultFun(e:FaultEvent):void
{
trace(e.toString() + " 1!!!");
}
//
private function onInvokeFun(e:InvokeEvent):void
{
trace(e.toString());
//trace(e.message.toString() + " ");
}
//
private function onResultFun(e:ResultEvent):void
{
trace(e.result + "End Result.");
// trace(e.headers + " headers");
// trace(e.message + " message");
// trace(e.messageId + " messages !");
// trace(e.statusCode + " statusCode");
// trace(e.target + " tager" );
// trace(e.token.responders + " token.responders ");
// trace(e.type);
}
]]>
</fx:Script>
<fx:Declarations>
<s:RemoteObject id="amf"  destination="zendAmf"  source="helloWorld" />
</fx:Declarations>
<s:layout>
<s:VerticalLayout horizontalAlign="center" verticalAlign="middle" />
</s:layout>
</s:Application>

<s:RemoteObject id="amf"  destination="zendAmf"  source="helloWorld" /> 
是設定你連結的方式!
id="amf" 是指你這個連線的名稱 後面用來呼叫函數 或是 監聽用的
destination="zendAmf" 就是你設定的  services-config.xml裡的 destination 的設定~
記的填一樣的~不然會報錯!
source 就是你servers的PHP的類別名稱


好了自己測試巴!
基本上你會先看到 InvokeEvent 代標有傳出呼叫了!
然後會有 onResultFun 近來!


到此兩種方式都介紹了!
個人是喜歡用 AS 的方式~
因為統一! 而且FLEX也可以用喔!


4.進接的應用VO的使用!
恩~依照 http://blog.corausir.org/programing/ausir-855的介紹!
基本上按照他的作都OK 
只有一步!在新的版本上~會報錯!
這個錯我找了很久~很久~
後來發現!不用設定

$server->setClassMap
$server->setClass
就可以直接對映!
這應該是新版本的威能!
所以我進行了一些測試!
基本上~只要在VO端加上
[RemoteClass(alias="PHP的類別")]
就可以直接 強制轉型!
var cv2:VO2 = e.result as VO2;
假設試不能轉的類型
會變成 null
假設兩個 AS的VO都設同一個 php class
只有最後設(讀到的)
可以強制轉型!
前面的就算有寫 RemoteClass
也會變能 null

好了整個zendAmf的部分 測試完成!
謝謝觀看!
順便記錄一下! 
基本上如個這個有下一篇應該試作和 amfphp 的一些測試評比
說一下心得
不過就一些簡單的傳輸來說~
我是看不出差別!
說真的這個比 amfphp 難設定!
目前我也沒發現簡易的後台~
像AMFPHP有一個試調和測試的介面!
如果有的話高手介紹一下!~
不然只好自己生了~~

不過兩個在轉換上應該問題不大!
目前只有一個超複雜破 三千行又include一堆東東的server跑不起來~
其他簡單的都是 OK的!

2011年11月15日 星期二

[AS3] 單機多重登入檢測

這個是大家都會的~
看在這個BLOG上啥都沒有的分上~
讓我用這個充一下版面


package com.tenchiwang.net
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.net.LocalConnection;

import mx.charts.chartClasses.DataDescription;

public class RepeatLoginManage extends EventDispatcher
{
public static const   ONLY_LOGIN:String = "onlyLogin";
public static const REPEAT_LOGIN:String = "rePeatLogin";

private var _name:String = 'localhost';
public var _lc:LocalConnection;
public var isRepeatLogin:Boolean = false; // false 沒有重複登入 true 有重複登入
// 檢查是否有重複登入
public function RepeatLoginManage(na:String = null)
{
_name = na?na:_name; // 字定的區隔 金鑰
_lc = new LocalConnection();
try{
_lc.connect(_name);
}catch(e:Error){
isRepeatLogin = true;
}
}
// 傳出 是否登入
public function init():void
{
if(!isRepeatLogin){
this.dispatchEvent(new Event(ONLY_LOGIN));
}else{
this.dispatchEvent(new Event(REPEAT_LOGIN));
}
}
// 結束 登入狀態
public function clearAll():void
{
if(!isRepeatLogin) _lc.close();
_lc = null;
}
}
}


Demo