[練習] Google Map API

0 意見

2009-04-28_225438.jpg

最近在看Google Map API,寫個簡單範例練習,點選新增可增加Marker至正中心,Marker可拖曳,點擊列表可移動地圖到指定Marker

程式原始碼

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
xmlns:maps="com.google.maps.*"
creationComplete="main();"
width="900" height="500"
enabled="false"
backgroundColor="0xFFFFFF" >
<mx:Script>
<![CDATA[
import mx.controls.dataGridClasses.DataGridColumn;
import mx.effects.Glow;
import mx.events.ListEvent;
import mx.controls.Alert;
import mx.rpc.events.FaultEvent;
import mx.managers.FocusManager;
import mx.events.FlexEvent;
import mx.rpc.events.ResultEvent;
import mx.collections.ArrayCollection;
import mx.controls.ColorPicker;
import mx.controls.Button;
import com.google.maps.overlays.MarkerOptions;
import com.google.maps.overlays.Marker;
import com.google.maps.controls.OverviewMapControl;
import com.google.maps.controls.ScaleControl;
import com.google.maps.controls.MapTypeControl;
import com.google.maps.controls.PositionControl;
import com.google.maps.controls.ZoomControl;
import com.google.maps.MapType;
import com.google.maps.LatLng;
import com.google.maps.MapOptions;
import com.google.maps.MapEvent;

[Bindable]
private var currentLatlng:LatLng;

[Bindable]
private var currentMarkers:ArrayCollection = new ArrayCollection([]);

private static const TAIWAN_LATLNG:LatLng = new LatLng(23.793120080412926, 121.12177848815918);
private static const DEFAULT_TOOLTIP_MESSAGE:String = "請輸入提示名稱";

private var iconArr:Array = [];

private function main():void
{
cursorManager.setBusyCursor();
toolTipMsg.text = DEFAULT_TOOLTIP_MESSAGE;
}

/**
* map生成完畢,加入控制項
*/
private function mapReadyhandler(event:MapEvent):void
{
var map:Map = Map(event.currentTarget);

//取消地形模式,mapTypeControl不會顯示
myMap.removeMapType(MapType.PHYSICAL_MAP_TYPE);

map.addControl(new ZoomControl());
map.addControl(new PositionControl());
map.addControl(new MapTypeControl());
map.addControl(new ScaleControl());
map.addControl(new OverviewMapControl());

myMap.addEventListener(MouseEvent.MOUSE_UP, function():void{updatePos();});

updatePos();
this.enabled = true;
cursorManager.removeBusyCursor();
}

/**
* map生成時設定初值
*/
private function mapPreInitHandler(event:MapEvent):void
{
var mapOption:MapOptions = new MapOptions();
mapOption.zoom = 8;
mapOption.center = TAIWAN_LATLNG;
mapOption.mapType = MapType.NORMAL_MAP_TYPE;

myMap.setInitOptions(mapOption);
}

private function updatePos():void
{
currentLatlng = myMap.getCenter();
}

private function addMarkerHandler(event:MouseEvent):void
{
var markerOptions:MarkerOptions = new MarkerOptions();
var iconClass:Class = house2;
var icon:DisplayObject = new iconClass();

icon.scaleX = icon.scaleY = .5;

markerOptions.icon = icon;
markerOptions.iconAlignment = MarkerOptions.ALIGN_HORIZONTAL_CENTER;
markerOptions.iconOffset = new Point(icon.width * .5, -icon.height * .5);
markerOptions.tooltip = toolTipMsg.text;
markerOptions.hasShadow = true;
markerOptions.draggable = true;

var marker:Marker = new Marker(currentLatlng, markerOptions);
myMap.addOverlay(marker);

currentMarkers.addItem({tooltip:toolTipMsg.text, marker:marker});
}

private function removeMarkerHandler(event:MouseEvent):void
{
var selectedItem:Object = markerList.selectedItem;
myMap.removeOverlay(selectedItem.marker);

currentMarkers.removeItemAt(currentMarkers.getItemIndex(selectedItem));
}

private function markerListClickHandler(event:ListEvent):void
{
var obj:Object = markerList.selectedItem;
var marker:Marker = obj.marker as Marker;

myMap.panTo(marker.getLatLng());
}

]]>
</mx:Script>
<mx:Style source="assets/css/style.css"/>

<mx:Label id="titleLbl"
styleName="titleStyle"
x="10" y="10"
text="Flex Google Map"
filters="{[new DropShadowFilter(0)]}"/>
<mx:HRule x="0" y="47" width="100%"/>

<mx:DataGrid id="markerList"
dataProvider="{currentMarkers}"
itemClick="markerListClickHandler(event)"
x="10" y="151" width="271" height="334"
fontSize="12">
<mx:columns>
<mx:DataGridColumn headerText="提示文字" dataField="tooltip"/>
</mx:columns>
</mx:DataGrid>

<mx:Button id="addBtn"
x="174" y="119"
label="新增"
click="addMarkerHandler(event)" fontWeight="normal" fontSize="12"/>

<mx:Button id="removeBtn"
x="232" y="119"
label="刪除"
enabled="{markerList.selectedIndex != -1}"
click="removeMarkerHandler(event)"
fontWeight="normal" fontSize="12"/>

<mx:Label text="緯度:{currentLatlng.lat()}" x="10" y="57" fontSize="12" selectable="true" width="272"/>
<mx:Label text="經度:{currentLatlng.lng()}" x="10" y="85" fontSize="12" selectable="true" width="272"/>

<mx:Canvas x="290" y="57" width="600" height="433" backgroundColor="#FFFFFF">
<!-- language = null 時會取瀏覽器語系-->
<maps:Map id="myMap"
key="ABQIAAAAkOcVHiQqdmsV1CsmWiycyxTJiUO4stL7mkJ7l2ZLr3ZW-k6zdxQnI6k1A5AlNMwoBRFxHhmOwAektQ"
mapevent_mapready="mapReadyhandler(event)"
mapevent_mappreinitialize="mapPreInitHandler(event)"
language=""
right="10" left="10" top="10" bottom="10"/>
</mx:Canvas>

<mx:TextInput id="toolTipMsg"
enter="addMarkerHandler(null)"
focusIn="toolTipMsg.text = ''"
x="10" y="119" width="156"
fontSize="12"/> </mx:Application>


官方教學:http://code.google.com/intl/zh-TW/apis/maps/documentation/flash/intro.html

GoogleCode:http://code.google.com/intl/zh-TW/apis/maps/documentation/flash/



[教學] Hello World BlazeDS

1 意見

繼上篇的Step by Step Blazeds後,介紹一下Blazeds的功能:Remoting、Message、Proxy

Remoting

概述

BlazeDS Remoting可使 Flash執行在伺服器上的 java程式,可傳值及接收結果, Remoting的傳輸格式是 AMF,格式較小且為二進位傳輸

使用 Remoting

先設定 "安裝目錄\WEB-INF\flex" 下的 remoting-config.xml,加入連線目的及要執行的 Java程式

<destination id="hello"> 
    <properties> 
        <source>idv.gd.HelloWorld</source> 
        <scope>application</scope> 
    </properties> 
</destination>

destination 為給 Flex 識別的連線名,source 為實際 java 程式所在位置,scope則可分成三種:

  1. application:建立單一 instance
  2. session:每個使用 session 建立一個 instance
  3. require(default):每次連線建立 instance

java存放路徑為 "安裝目錄\WEB-INF\classes",放置位置同 Java package路徑(ex:安裝目錄\WEB-INF\classes\idv\gd\HelloWorld.class) 可執行的檔案為 Java編譯後的檔案(*.class),範例使用了三個方法,程式源始碼如下

package idv.gd; 
 
public class HelloWorld{   
 
     public String getHello(){    
                return "Hello world"; 
     } 
 
     public String sendMsg(String str){    
                String serverMsg = "[Server]你說的話是:" + str; 
                return serverMsg; 
     } 
 
     public Object sendObj(Object obj){   
               return obj;
     } 
}

Remoting VO

Flex特有的 "RemoteClass" metadata 是用來指出 Flex 與伺服器上的 VO物件,只要在後面加入伺服器 VO位置,就能自動對應,可傳遞相同的 VO物件。

本地 VO

package vo{    
        //用來連結遠端的 java object,名稱路徑要相符 
        [RemoteClass (alias = "idv.gd.MyVO")] 
        public class MyVO{    
                //parameters 要相符,可有多餘參數 
                public var userName:String; 
                public var userPWD:String; 
 
             //public var extraParam:Object; 
 
             public function MyVO(userName:String = null, userPWD:String = null){    
                        this.userName = userName; 
                        this.userPWD = userPWD; 
             } 
     } 
}

伺服器 VO

package idv.gd; 
 
public class MyVO{    
        public String userName; 
        public String userPWD; 
}

兩對應之 VO參數要相符,路徑要正確,VO路徑不必含副檔名(idv.gd.MyVO),設定好後,Flex跟伺服器就可傳相同的 VO物件了

範例程式為傳送 VO給伺服器,伺服器收到後回傳 "server" + 原始訊息的 VO給 Flash 主程式:

<?xml version="1.0" encoding="utf-8"?> 
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="main();"> 
        <mx:Script> 
                <![CDATA[ 
                        import mx.rpc.remoting.RemoteObject; 
                        import mx.rpc.events.FaultEvent; 
                        import mx.rpc.events.ResultEvent; 
                        import vo.MyVO; 
                        private function main():void{    
                                var myRO:RemoteObject = new RemoteObject(); 
 
                             myRO.destination = "VOTest"; 
 
                             myRO.getVO.addEventListener(ResultEvent.RESULT, resultHandler); 
                                myRO.getVO.addEventListener(FaultEvent.FAULT, resultHandler); 
 
                             var myVO:MyVO = new MyVO(); 
                                myVO.userName = "GD"; 
                                myVO.userPWD = "123"; 
 
                             myRO.getVO(myVO); 
                     } 
 
                     private function resultHandler(event:ResultEvent):void{    
                                var myVO:MyVO = MyVO(event.result); 
                                msg.text = myVO.userName + "\n" + myVO.userPWD; 
                     } 
 
                     private function faultHandler(event:FaultEvent):void{    
                                msg.text = event.message.toString(); 
                     } 
                ]]> 
        </mx:Script> 
 
     <mx:TextArea id="msg" top="10" bottom="10" left="10" right="10"/> 
</mx:Application>

Java:

package idv.gd; 
 
public class Contact{    
        public MyVO getVO(MyVO vo){    
                vo.userName = "server=" + vo.userName; 
                vo.userPWD = "server=" + vo.userPWD; 
 
             return vo; 
     } 
}

程式原始碼

<?xml version="1.0" encoding="utf-8"?> 
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="800" height="600" applicationComplete="main();"> 
        <mx:Script> 
                <![CDATA[ 
                        import flash.utils.getQualifiedClassName; 
                        import flash.utils.getDefinitionByName; 
                        import mx.rpc.events.FaultEvent; 
                        import mx.rpc.events.ResultEvent; 
 
                     private function main():void{    
                                //直接把 Java的方法當實體註冊 
                                myRO.getHello.addEventListener(ResultEvent.RESULT, resultHandler); 
                                myRO.sendMsg.addEventListener(ResultEvent.RESULT, resultHandler); 
                                myRO.sendObj.addEventListener(ResultEvent.RESULT, resultTypeHandler); 
 
                             myRO.getHello.addEventListener(FaultEvent.FAULT, faultHandler); 
                                myRO.sendMsg.addEventListener(FaultEvent.FAULT, faultHandler); 
                                myRO.sendObj.addEventListener(FaultEvent.FAULT, faultHandler); 
 
                             //呼叫 Java方法 
                                myRO.getHello(); 
 
                             //試著傳送物件型態資料 
                                myRO.sendObj({   name:"myName", age:18}); 
 
                             //試著傳送陣列型態資料 
                                myRO.sendObj(["myName", 18]); 
                     } 
 
                     private function faultHandler(event:FaultEvent):void{    
                                msg.text += event.message + "\n"; 
                     } 
 
                     private function resultHandler(event:ResultEvent):void{    
                                msg.text += event.result + "\n"; 
                     } 
 
                     private function resultTypeHandler(event:ResultEvent):void{    
                                msg.text += getQualifiedClassName(event.result) + "\n"; 
                     } 
 
                     private function sendMsg():void{    
                                myRO.sendMsg(inputMsg.text); 
                     } 
                ]]> 
        </mx:Script> 
        <mx:RemoteObject id="myRO" destination="hello" result="resultHandler(event)" fault="faultHandler(event)" /> 
 
     <mx:Button x="178" y="393" label="send" click="sendMsg()"/> 
        <mx:TextInput x="10" y="393" id="inputMsg"/> 
        <mx:TextArea x="10" y="45" width="502" height="340" id="msg" fontSize="12" /> 
        <mx:Label x="10" y="10" text="RemoteObject 測試" fontSize="16" fontWeight="bold"/> 
</mx:Application>

BlazeDS Message

概述

Message 可讓多使用者與伺服器溝通,彼此的訊息都會被廣播,可簡單作出聊天室的效果

使用 Message

首先在 "專案目錄\WEB-INF\flex"下有個 messaging-config.xml 的設定檔,打開後加入一個連線識別名

<destination id="chat"/>

整體設定檔如下

<?xml version="1.0" encoding="UTF-8"?> 
<service id="message-service" 
    class="flex.messaging.services.MessageService"> 
 
    <adapters> 
        <adapter-definition id="actionscript" class="flex.messaging.services.messaging.adapters.ActionScriptAdapter" default="true" /> 
        <!-- <adapter-definition id="jms" class="flex.messaging.services.messaging.adapters.JMSAdapter"/> --> 
    </adapters> 
 
    <default-channels> 
        <channel ref="my-polling-amf"/> 
    </default-channels> 
 
    <destination id="chat"/> 
 
</service>

開啟設定好的 Flex 專案,使用 consumer、producer與 message 連線,consumer是負責接收來自message的訊息,而 producer 則是負責發送訊息,以下設定 consumer及 producer

<mx:Producer id="myProducer" destination="chat" fault="faultHandler(event);" channelConnect="connectHandler(event)"/> 
 
<mx:Consumer id="myConsumer" destination="chat" message="messageHandler(event)" fault="faultHandler(event);" channelConnect="connectHandler(event)"/>

在設定完後並未連線,跟 HttpService一樣,producer需透過 send()指令送出訊息,而 consumer則是以subscribe()訂閱 message訊息

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="main()"> 
<mx:script> 
 
//一開始先把consumer連線 
private function main():void{    
        myConsumer.subscribe(); 
} 
 
private function sendMsg():void{    
        var message:IMessage = new AsyncMessage(); 
 
     //body是一個物件 
        message.body.chatMessage = inputMsg.text; 
 
     myProducer.send(message); 
 
     inputMsg.text = ""; 
}

producer 送出的訊息是一個 AsyncMessage物件,裡面的 body為實際傳送值,型態為物件,可再自定義屬性,範例為送出 chatMessage屬性做為聊天訊息,設定好後執行兩隻程式即可對話。

程式原始碼

<?xml version="1.0" encoding="utf-8"?> 
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="main()"> 
        <mx:Script> 
                <![CDATA[ 
                        import mx.messaging.events.ChannelEvent; 
                        import mx.messaging.events.MessageFaultEvent; 
                        import mx.rpc.events.FaultEvent; 
                        import mx.messaging.events.MessageEvent; 
                        import mx.messaging.messages.AsyncMessage; 
                        import mx.messaging.messages.IMessage; 
 
                     //一開始先把consumer連線 
                        private function main():void{    
                                myConsumer.subscribe(); 
                     } 
 
                     private function sendMsg():void{    
                                var message:IMessage = new AsyncMessage(); 
 
                             //body是一個物件 
                                message.body.chatMessage = inputMsg.text; 
 
                             myProducer.send(message); 
 
                             inputMsg.text = ""; 
                     } 
 
                     private function messageHandler(event:MessageEvent):void{    
                                chatDialog.text += event.message.body.chatMessage + "\n"; 
                     } 
 
                     private function faultHandler(event:MessageFaultEvent):void{    
                                chatDialog.text += event.faultDetail; 
                     } 
 
                     private function connectHandler(event:ChannelEvent):void{    
                                chatDialog.text += event.type + " connect\n"; 
                     } 
                ]]> 
        </mx:Script> 
        <mx:Producer id="myProducer" destination="chat" fault="faultHandler(event);" channelConnect="connectHandler(event)"/> 
        <mx:Consumer id="myConsumer" destination="chat" message="messageHandler(event)" fault="faultHandler(event);" channelConnect="connectHandler(event)"/> 
 
     <mx:Button x="178" y="358" label="send" click="sendMsg()"/> 
        <mx:TextInput x="10" y="358" id="inputMsg"/> 
        <mx:TextArea x="10" y="10" width="502" height="340" id="chatDialog"/> 
</mx:Application>

BlazeDS Proxy

概述

Proxy可以解決 Flash的跨網域安全性問題,使原本無法存取的遠端網站,藉由本地伺服器存取後再轉給 Flash,如此就不會有 crossdomain的問題,且使用BlazeDS 設定非常方便,也能隨時置換要存取的位置,不必修改 Flash

使用 Proxy

首先在 "專案目錄\WEB-INF\flex"下有個 proxy-config.xml 的設定檔,打開後會看到裡面己有 DefaultHTTP 的 desination,這是用來告訴伺服器,當 Flash 要存取 HTTP 資源時,那些網域要透過伺服器代理處理,透過 <dynamic-url>標籤指定網域,可使用萬字元(*)

  <destination id="DefaultHTTP"> 
        <properties> 
            <dynamic-url>http://tw.news.yahoo.com/*</dynamic-url> 
        </properties> 
  </destination>

使用 Flex 連線 dynamic-url: 跟平常的設定一樣,還是使用 url做連結,只是 useProxy要設為 true,讓連線去找伺服器設定

<mx:HTTPService id="dynamicHS" 
        url="http://tw.news.yahoo.com/rss/realtime" 
        result="resultHandler(event)" 
        resultFormat="e4x" 
        showBusyCursor="true" 
        fault="faultHandler(event);" 
        useProxy="true" />

自定義 proxy: 可使用 destination id 作為與 flash的連線識別,告訴 Flash連到 destination 要轉到那個網址去,雖然是外部網址,但Flash是透過本地伺器取值,所以不會有 crossdomain的問題

    <destination id="myRSS"> 
        <properties> 
           <url>http://portofreturn.pixnet.net/blog/feed/rss</url> 
        </properties> 
    </destination>

使用 Flex 連線 destination proxy: 使用 destination取代 url,useProxy一樣要設為 true

<mx:HTTPService id="proxyHS" 
        destination="myRSS" 
        result="proxyResultHandler(event)" 
        resultFormat="e4x" 
        showBusyCursor="true" 
        fault="faultHandler(event);" 
        useProxy="true" />

使用 Webservice: 基本設定大致相同,但伺服器端要設定以 soap方式傳輸

    <adapters> 
        <adapter-definition id="http-proxy" class="flex.messaging.services.http.HTTPProxyAdapter" default="true"/> 
        <adapter-definition id="soap-proxy" class="flex.messaging.services.http.SOAPProxyAdapter"/> 
    </adapters> 
 
  <destination id="infoService"> 
      <properties> 
          <wsdl>http://livecycledata.org/services/ProductWS?wsdl</wsdl> 
          <soap>*</soap> 
      </properties> 
      <adapter ref="soap-proxy"/> 
  </destination>

程式原始碼

<?xml version="1.0" encoding="utf-8"?> 
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" backgroundGradientAlphas="[1.0, 1.0]" backgroundGradientColors="[#333333, #000000]"> 
        <mx:Script> 
                <![CDATA[ 
                        import mx.rpc.events.FaultEvent; 
                        import mx.rpc.events.ResultEvent; 
 
                     [Bindable] 
                        private var rssPath:String = "http://portofreturn.pixnet.net/blog/feed/rss"; 
 
                     private var xml:XML; 
 
 
 
                     private function resultHandler(event:ResultEvent):void{    
                                xml = new XML(event.result); 
                                msg.text = xml.toXMLString(); 
                     } 
 
                     private function proxyResultHandler(event:ResultEvent):void{    
                                //xml = new XML(event.result.body); 
                                msg.text = "proxy\n"; 
                                msg.text += event.result; 
                     } 
 
                     private function faultHandler(event:FaultEvent):void{    
                                msg.text = String(event.message); 
                     } 
 
                     private function getRSS(url:String):void{    
                                rssPath = url; 
                                myHS.send(); 
                     } 
                ]]> 
        </mx:Script> 
        <mx:HTTPService id="myHS" 
                url="{   rssPath}" 
                result="resultHandler(event)" 
                resultFormat="e4x" 
                showBusyCursor="true" 
                fault="faultHandler(event);" /> 
 
     <mx:HTTPService id="proxyHS" 
                destination="myRSS" 
                result="proxyResultHandler(event)" 
                resultFormat="e4x" 
                showBusyCursor="true" 
                fault="faultHandler(event);" 
                useProxy="true" /> 
 
     <mx:HTTPService id="dynamicHS" 
                url="http://tw.news.yahoo.com/rss/realtime" 
                result="resultHandler(event)" 
                resultFormat="e4x" 
                showBusyCursor="true" 
                fault="faultHandler(event);" 
                useProxy="true" /> 
 
     <mx:TextArea left="10" bottom="10" top="41" right="10" id="msg" fontSize="12"/> 
        <mx:ApplicationControlBar left="0" right="0" top="0"> 
                <mx:Button label="Local RSS" click="getRSS('rss.xml');"/> 
                <mx:Button label="pixnet RSS" click="getRSS('http://portofreturn.pixnet.net/blog/feed/rss')"/> 
                <mx:Button label="Chanwei RSS" click="getRSS('http://chanwei.dev.kland.com.tw/security/rss.xml')"/> 
                <mx:Button label="Proxy RSS" click="proxyHS.send();"/> 
                <mx:Button label="dynamic RSS" click="dynamicHS.send();"/> 
        </mx:ApplicationControlBar> 
</mx:Application>

轉載請註明出處



[教學] Step by Step BlazeDS

1 意見

把之前的筆記整理上來,介紹一下BlazeDS

什麼是BlazeDS?

BlazeDS是Adobe開發的免費開源軟體,提供了Java-Base的remoting 及 web messaging服務,可讓Flex、AIR等應用程式簡單與後端連線、建立及發送資料,且伺服器可主動更新,提供更完整的RIA使用經驗。

BlazeDS、LiveCycle比較

LCDS(LiveCycle Data Services)為Adobe的付費方案,提供完整的網路服務,而BlazeDS則是由LiveCycle分出的資料處理功能(Remoting、Message),這部分是完全免費且開源,以下列表比較LiveCycle與BlazeDS的功能差異(轉載自http://sujitreddyg.wordpress.com/2008/01/31/blazeds-and-lcds-feature-difference/

Features

BlazeDS

LCDS

Data management Services
Client-Server synchronization
Conflict resolution
Data paging
SQL adapter
Hibernate adapter
Document Services
LiveCycle remoting
RIA-to-PDF conversion
Enterprise-Class Flex application services
Data access/remoting
Proxy service
Automated testing support
Software clustering
Web tier compiler
Enterprise Integration
WSRP generation
Ajax data services
Flex-Ajax bridge
Runtime configuration
Open adapter architecture
JMS adapter
Server-side component framework integration
ColdFusion integration
Offline Application Support
Offline data cache
Local message queuing
Real - Time Data
Publish and Subscribe messaging
Real -time data quality of service
RTMP tunneling

安裝方案一:BlazeDS turnkey

BlazeDS turnkey為Adobe官網所發佈的BlazeDS整合版,該版本己含Tomcat6、BlazeDS、HSQLDB、Flex SDK及官方範例,內容完整描述BlazeDS所有功能,建議一開始可安裝此版本練習。

Step1.下載所需檔案

  1. BlazeDS turnkey 官方下載頁 請下載 Turnkey 版
  2. Java官方下載頁 請下載 j2sdk

Step2. 建立執行環境

  1. 把下好的BlazeDS turnkey解壓縮,把資料夾下tomcat及sampledb 放在根目錄或喜好的執行路徑(ex: c:\blazeds\tomcat、c:\blazeds\sampledb)
  2. 安裝下好的JavaSE SDK
  3. 在控制台的系統 ─> 進階 ─> 環境變數的系統變數下加入─ 變數 = "JAVA_HOME",值 = JDK所在位置(ex:C:\Program Files\Java\jdk1.6.0_11)
  4. 環境變數的path也可順便加入JDK所在位置,方便日後編輯Java程式,記得參數間以";"分開

Step3. 執行 Tomcat、HSQLDB

  1. 開始 ─> 執行 ─> cmd,進入命令提示列,找到你所放置的sampledb位置,輸入 "startdb" 按下確定以啟動資料庫(這資料庫是給官方範例用的)
  2. 同樣在命令提示列,找到你所放置的tomcat位置,輸入 "startup" 按下確定以啟動Tomcat Web Server
  3. 在瀏覽器輸入 localhost:8400(埠號預設為8400,可在tomcat/conf/server.xml的Connector進行修改)
  4. 出現BlazeDS的選單就成功了,如果有問題請仔細看命令提示列結果,並確認JAVA_HOME是否有設好 備註:關閉TomcatServer 請輸入 "shutdown" 指令

安裝方案二:Tomcat + BlazeDS

單純的 Tomcat Web Server 加上 BlazeDS,沒有範例但架設簡單,簡單測試可嘗試此安裝法

Step1. 下載所需檔案

  1. ApacheTomcat官方下載頁 請下載 Tomcat6 Windows Service Installer 版本
  2. BlazeDS官方下載頁 請下載 Binary Distribution 版本

Step2. 建立執行環境

  1. 點擊安裝 apache-tomcat
  2. 解壓縮下好的 blazeds-bin,會有一個叫 blazeds.war 的檔案,由壓縮軟體解壓縮,裡面有 META-INF、WEB-INF 兩個資料夾,建立一個資料夾(ex:blazeds),把這兩個資料夾放到資料夾內,並移至 Tomcat 安裝目錄下的 webapps(ex: C:\Program Files\Apache Software Foundation\Tomcat 6.0\webapps\blazeds)

Step3. 執行 Tomcat

  1. 開始 ─> 程式集 ─> Apache Tomcat6,執行 Monitor Tomcat
  2. 在ApacheTomcat Properities 點選 general 標籤,點選下方的start啟用 Tomcat
  3. 同位置點選 stop 可以關閉 Tomcat
  4. 在瀏覽器輸入 localhost:8080(port 8080 為安裝預設值),出現 Tomcat管理畫面即成功安裝

Tomcat、BlazeDS結構說明

Tomcat目錄結構 取自Tomcat wiki,Blazeds要放在webapps裡

$CATALINA_HOME Tomcat安裝目錄 ├─bin 用以啟動、關閉Tomcat或者其他功能的腳本(.bat文件和.sh文件) ├─common Catalina和Web應用程序會用到的Class及庫文件 ├─conf 用以配置Tomcat的XM及DTD文件 ├─logs Catalina和其他Web應用程序的日誌文件 ├─server Catalina用到的Class及庫文件 ├─shared Web應用程序用到的Class及庫文件 ├─temp 臨時文件 ├─webapps Web應用程序根目錄 └─work 用以產生有JSP編譯出的Servlet的.java和.class文件

Blazeds目錄結構 BlazeDS是由兩個資料夾構成,META-INF、WEB-INF,這兩個檔案可在Tomcat webapps下以目錄做區別,每個webapps 下的目錄只會參照到自己的META-INF、WEB-INF,例如: webapps/blazeds/ 跟 webapps/she/ 下各有META-INF、WEB-INF,每個資料夾內的檔案都只會參照自己的META-INF、WEB-INF設定

$BLAZEDS_HOME Blazeds 安裝目錄 ├─META-INF └─WEB-INF BlazeDS 的設定檔 ├─classes 要執行的 Java 程式(*.class) ├─flex 可設定 Flex、AIR 要取用的服務設定檔,包含remoting、message、proxy ├─lib └─src

建立 BlazeDS開發環境

使用 BlazeDS turnkey:

  1. 在 tomcat/webapps 下有一個 blazeds 資料夾,這個為blazeds 的基本元件及設定檔,請複製同一資料夾並改名
  2. 改名資料夾即可做為BlazeDS的開發環境,請將swf或Flex專案設在此資料夾內
  3. turnkey 有所有範例的源始碼,檔案在 tomcat/webapps/samples/WEB-INF/flex/flex-src 下

使用 Tomcat + BlazeDS

  1. 請把之前解壓縮的檔案(blazeds.war 參照 "安裝方案二:Tomcat + BlazeDS")放在 tomcat/webapps 資料夾下,每次使用請複製同一資料夾並改名
  2. 改名資料夾即可做為BlazeDS的開發環境,請將swf或Flex專案設在此資料夾內

建立 Flex 開發環境

  1. New Flex Project 在Server Technology中選擇 "J2EE",並把 use remote object access 打開,點選下一步 設定 Server location 的路徑
  2. Root folder 為你的程式執行位置(ex:C:\Blazeds\tomcat\webapps\myTest)
  3. Root URL 為對應的web伺服器位置(ex:http://localhost:8400/myTest/)
  4. content Root 為該執行目錄的根,基本上要跟執行目錄相同(ex:/myTest)
  5. 設定完後點選 Validate Configuration 驗證設定
  6. 點選下一步
  7. 之後發佈就會自動把程式放在執行位置,並以伺服器位置打開,可直接發佈Flex測試

總結

  1. BlazeDS 完全免費且開源
  2. BlazeDS 可解決跨網域問題(Flash 安全性)
  3. BlazeDS 的 RemoteObject 是以 AMF 作傳輸,比傳統要快
  4. BlazeDS Message伺服器可主動送訊息給使用者

BlazeDS 免費且方便,解決了大部分 Flex 溝通及安全性的問題,BlazeDS 與 Flex的連線請參照Helloworld Blazeds

轉載請註明出處



好用的網站開發工具─Charles

2 意見

2009-04-20_230914.jpg

介紹一個好用的開發工具Charles,Charles可觀看目前網頁的狀態,可得知被載入的檔案以及傳收的值(類似HttpWatch),比較特殊的是他可限制流量,模擬下載頻寬,對Flex這種沒有模擬頻寬的開發工具來說,非常好用,且Charles也可觀看loadMovie、loadVariables及Flash Remoting,並支援IE、Firefox及Safari,非常強大,有興趣的朋友可以試試。

2009-04-20_231923.jpg

Firefox記得要加裝add-on,如果沒有JRE也要先裝

Charles:http://www.charlesproxy.com/index.php



Unity 3D

2 意見

2009-04-19_005136.jpg

雖然Unity早己不是新聞,但還是要介紹一下,因為他的效果實在太強大了

Flash 3D 的解決方案,一般不外乎是FP10原生的3D功能或是第三方的 Papervision3D、Away3Dl、Candy3D等,雖然功能愈來愈多,但缺點就是太耗資源,由於Flash運算仍以CPU為主(只有部分是透過GPU),即使在FP10加速了三角繪製及型別陣列,但3D效果仍有限,而Unity就不同了,Unity可以調用GPU來處理3D效果,速度自然更快,在光影的表現也是PV3D所不能及的,而且Unity的運行方式同Flash Player,只要能加掛Player的平台都能運行,所以Unity也有windows版、Mac版甚至是iPhone版,跨平台的特性以及華麗的效果,令人不得不在意他後繼的發展。

2009-04-19_005043.jpg

這裡有Unity的範例,有如此良好的3D能力,以後要開發3D MMOGame也不是不可能,也希望Adobe快醒醒,Silverlight 3都要支援GPU了,Flash還在等什麼?

Unity DEMO:http://unity3d.com/gallery/live-demos/tropical-paradise

官方網頁:http://unity3d.com/



Flash 2.5D引擎 ffilmation

0 意見

2009-04-19_015028.jpg

ffilmation是一個2.5D引擎,可用來開發常見的俯側視角的遊戲,效果不錯,但影子渲染感覺有點慢,有興趣的朋友可以看看

官網:http://www.ffilmation.org/website/



[練習]3D物理引擎 jiglibflash

0 意見

2009-04-19_011913.jpg

jiglibflash是為Flash 3D開發的物理引擎,支援常見的3D引擎,包括PV3D、Away3D,由於寫起來是直接使用3D座標,所以撰寫方便,也支援不規則模形的物件,比我之前看過的WOW引擎功能多很多,但缺點還是太吃CPU資源

package {
import flash.display.Bitmap;
import flash.events.Event;
import flash.events.MouseEvent;

import jiglib.math.JNumber3D;
import jiglib.physics.PhysicsSystem;
import jiglib.physics.RigidBody;
import jiglib.physics.constraint.JConstraintWorldPoint;
import jiglib.plugin.papervision3d.Papervision3DPhysics;

import org.papervision3d.core.geom.renderables.Vertex3D;
import org.papervision3d.core.math.Number3D;
import org.papervision3d.core.math.Plane3D;
import org.papervision3d.core.utils.Mouse3D;
import org.papervision3d.events.InteractiveScene3DEvent;
import org.papervision3d.lights.PointLight3D;
import org.papervision3d.materials.BitmapMaterial;
import org.papervision3d.materials.ColorMaterial;
import org.papervision3d.materials.shadematerials.FlatShadeMaterial;
import org.papervision3d.materials.utils.MaterialsList;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.view.BasicView;
import org.papervision3d.view.layer.ViewportLayer;
import org.papervision3d.view.layer.util.ViewportLayerSortMode;
       /**
* 
* @author GD
* 
*/     
[SWF (width = "950", height = "500", frameRate = "30", backgroundColor = "0xFFFFFF")]
public class Main extends BasicView
{
private static const WORLD_WIDTH:uint = 950;

private var physics:Papervision3DPhysics;
private var pointLight:PointLight3D;

private var mouse3D:Mouse3D;
private var currentBody:RigidBody;
private var planeToDragOn:Plane3D;
private var dragConstraint:JConstraintWorldPoint

[Embed (source = "assets/floor.jpg")]
private var floorAsset:Class;

public function Main()
{
super(950, 500, true, true);

initPV3D();
initJiglib();

createFloor();
createBox(5);

stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);                    
startRendering();
}

private function initJiglib():void
{
//創銉物理world並指定元件要加入的scene
physics = new Papervision3DPhysics(scene, 8);   
}

private function initPV3D():void
{
pointLight = new PointLight3D();
pointLight.y = 1000;
pointLight.z = -800;
viewport.containerSprite.sortMode = ViewportLayerSortMode.INDEX_SORT;

Mouse3D.enabled = true;
mouse3D = viewport.interactiveSceneManager.mouse3D;

camera.z = -1200;
camera.y = 300;
camera.rotationX = 45;
}

private function createFloor():void
{
var colorMat:ColorMaterial = new ColorMaterial(0xCCCCCC);
var imageMat:BitmapMaterial = new BitmapMaterial(Bitmap(new floorAsset()).bitmapData);
var listMat:MaterialsList = new MaterialsList({all:colorMat, top:imageMat});

//createCube會創建物理的body跟實際的pv3d元件(會自動加入至pv3d scene)
var floorBody:RigidBody = physics.createCube(listMat, 1600, 1200, 10);

var floor3D:DisplayObject3D = physics.getMesh(floorBody);

//fix
floorBody.movable = false;
floorBody.moveTo(new JNumber3D(0, -300, 0));
floorBody.restitution = .8;
floorBody.friction = .2;

//重調整layer層次
viewport.getChildLayer(floor3D).layerIndex = 1;
}

private function createBox(num:uint):void
{
//重調整layer層次,在floor前,內部照z軸排序
var modelLayer:ViewportLayer = new ViewportLayer(viewport, null);

modelLayer.sortMode = ViewportLayerSortMode.Z_SORT;
modelLayer.layerIndex = 2;
viewport.containerSprite.addLayer(modelLayer);  

var cubeWidth:uint = 150;
var cubeHeight:uint = 150;
var cubeDepth:uint = 150;

for (var i:uint; i < num; i++)
{
var ranX:Number = Math.random() * 1200 - 600;
var ranY:Number = Math.random() * 500 + 500;
var ranZ:Number = Math.random() * 800 - 400;

var flatMat:FlatShadeMaterial = new FlatShadeMaterial(pointLight, Math.random() * 0x1000000, 0x111111);
var listMat:MaterialsList = new MaterialsList({all:flatMat});

var cube:RigidBody = physics.createCube(listMat, cubeWidth, cubeDepth, cubeHeight);
var cube3D:DisplayObject3D = physics.getMesh(cube);

cube.moveTo(new JNumber3D(ranX, ranY, ranZ));
modelLayer.addDisplayObject3D(cube3D);

flatMat.interactive = true;     
cube3D.addEventListener(InteractiveScene3DEvent.OBJECT_PRESS, mousePressHandler);
}
}

private function findBody(obj3D:DisplayObject3D):RigidBody
{
var bodys:Array = PhysicsSystem.getInstance().bodys;
var rigidBody:RigidBody;

for each (var body:RigidBody in bodys)
{
var skinObj:DisplayObject3D = physics.getMesh(body);
if (skinObj == obj3D)
{
rigidBody = body;
break;
}
}
return rigidBody;
}

private function mousePressHandler(event:InteractiveScene3DEvent):void
{
trace("press");
//創立constraint
var startPos:JNumber3D = new JNumber3D(mouse3D.x, mouse3D.y, mouse3D.z);
currentBody = findBody(event.displayObject3D);
planeToDragOn = new Plane3D(new Number3D(0, 0, -1), new Number3D(0, 0, -startPos.z));

var bodyPoint:JNumber3D = JNumber3D.sub(startPos, currentBody.currentState.position);
dragConstraint = new JConstraintWorldPoint(currentBody, bodyPoint, startPos);
PhysicsSystem.getInstance().addConstraint(dragConstraint);

stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
}

private function mouseUpHandler(evnet:MouseEvent):void
{
if (dragConstraint)
{
PhysicsSystem.getInstance().removeConstraint(dragConstraint);
dragConstraint = null;
currentBody.setActive();
stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
}
}

private function mouseMoveHandler(event:MouseEvent):void
{
var ray:Number3D = camera.unproject(viewport.containerSprite.mouseX, viewport.containerSprite.mouseY);
ray = Number3D.add(ray, new Number3D(camera.x, camera.y, camera.z));

var cameraVertex3D:Vertex3D = new Vertex3D(camera.x, camera.y, camera.z);
var rayVertex3D:Vertex3D = new Vertex3D(ray.x, ray.y, ray.z);
var intersectPoint:Vertex3D = planeToDragOn.getIntersectionLine(cameraVertex3D, rayVertex3D);

dragConstraint.worldPosition = new JNumber3D(intersectPoint.x, intersectPoint.y, intersectPoint.z);
}

override protected function onRenderTick(event:Event=null):void
{
physics.step();
super.onRenderTick(event);
}
}
}

jiglibflash google code:http://code.google.com/p/jiglibflash/



[練習]PV3D + BOX2D + IK

0 意見
2009-04-18_000509.jpg
Box2D是非常強力2D物理引擎,這次試著把之前的作品透過一些小技巧應用到PV3D,效果不錯,不過還蠻吃資源的
原始檔下載


[網站推薦] Labuat

0 意見

2009-04-15_214956.jpg

美妙的音樂加上活潑的線條,不得不佩服外國人的創意

http://soytuaire.labuat.com/



[練習]PV3D人物互動

6 意見

最近都在看framework,偶爾也來練習一下PV3D,這次是練習DAEMC跟座標定位,寫了一個3D Game常見的人物互動,寫得更精緻點也能像遊戲一樣,有空再來研究

2009-04-13_232755.jpg

點擊地面移動人物,方向鍵可改變視角

模型來自http://www.tomtallian.com/

程式原始碼



3D拼圖

0 意見

2009-04-09_183320.jpg

將Flash 3D應用到拼圖遊戲,個人覺得還蠻有創意的

http://www.pearljamtengame.com/



[教學][PureMVC]使用Fabrication與Module溝通

0 意見

之前有介紹過Pipes Util,雖然Pipes能有效解決PureMVC與Module間溝通的問題,但寫起來實在太繁雜了,在此介紹一個簡單又好用的工具─Fabrication,Fabrication一樣是PureMVC的Util,最大的特徵是能簡化PureMVC的撰寫,包括宣告跟註冊事件,且最令人感心的是連Pipes都簡化了,不用再宣告一大堆管子、連結器什麼有的沒的,只要用PureMVC類似的Notification機置就能完成,寫起來真的是方便許多。

寫個簡單範例,這個範例跟上次的PureMVC + Pipes功能相同,可以拿來做個比較

程式架構

2009-04-08_182938.jpg

Main為Loader,MyModule為Loadee,程式為實做Main跟MyModule溝通

在Fabrication內,Facade會被隱藏起來,所以是沒有Facade的Class,取而代之的是一開始進入的StartupCommand,為了管理Notification,範例另存一個常數的Class,並放在common,方便所有Module操作

<?xml version="1.0" encoding="utf-8"?>
<fab:FlexApplication
xmlns:fab="org.puremvc.as3.multicore.utilities.fabrication.components.*" 
xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
creationComplete="init();" fontSize="12">

<mx:Script>
<![CDATA[
import idv.gd.hellofabrication.shell.controller.ApplicationStartupCommand;

override public function getStartupCommand():Class
{
return ApplicationStartupCommand;
}
]]>
</mx:Script>

<fab:FlexModuleLoader id="moduleLoader" x="317"/>

<mx:TextInput id="sendMsg"  width="160" x="0" y="30"/>
<mx:Button id="sendBtn" label="Send" y="30" x="168"/>
<mx:Label x="0" y="2" text="Shell"/>
<mx:Button x="235" y="30" label="Info" id="infoBtn"/>
</fab:FlexApplication>

首先繼承Fabrication內的FlexApp(AIR用AirApp),在一開始指定要呼叫的起始命令,要注意的是StartCommand的前置詞會被Fabrication設成ClassName,這是用來識別Shell跟Module的,所以在命名上小心別重覆了

由於沒有Facade,所以透過StartupCommand來宣告所有的controller,由於StartupCommand正常上只會被執行一次,所以不必憺心會重覆宣告(範例僅用到registerMediator)

package idv.gd.hellofabrication.shell.controller
{
import idv.gd.hellofabrication.shell.view.ApplicationMediator;

import org.puremvc.as3.multicore.interfaces.INotification;
import org.puremvc.as3.multicore.utilities.fabrication.patterns.command.SimpleFabricationCommand;

public class ApplicationStartupCommand extends SimpleFabricationCommand
{               
override public function execute(notification:INotification):void
{
var main:Main = notification.getBody() as Main;

registerMediator(new ApplicationMediator(main));                        
}
}
}

Mediator需繼承自FlexMediator,Fabrication的Mediator能透過onRegister去註冊方法,取代PureMVC原本的interestedList跟Switch case,只要方法下reactTo、respondTo關鍵字就能分別聽到Event跟Notification,這是Fabrication最特殊的Reflexive功能,比較可惜的是由於Reflexive是透過describeType倒出,所以方法只能下Public,失去程式封裝的原則,寫起來是很方便,但要小心拼錯是不會跳錯誤的,改常數名字時也是一個大工程...。(還是可用PureMVC的方式宣告,FlexMediator是繼承自Mediator)

格式大致如下:

reactTo <物件> <事件名> (event:<對應事件>)

respondTo <Notification名稱> (note:INotification)

再來就是最重要的Module溝通了,Fabrication能藉由Pipes做Module溝通(Pipes要另外匯入),只要一開始有把Module的defaultRouteAddress跟router設為Shell的applicationAddress、applicationRouter即可,之後再透過routeNotification來傳送通知,當然也能指定要送給誰,在routeNotification的第四個參數可決定傳送對象,"*"為全部,過濾格式為 <Class name/ instance name>,Class name就是我們之前宣告的StartupCommand的前置詞,也能使用flexModule.moduleAddress.getClassName()來取得Module名稱

ApplicationMediator

package idv.gd.hellofabrication.shell.view
{
import flash.events.MouseEvent;

import idv.gd.hellofabrication.common.RouteConst;

import mx.controls.Alert;
import mx.controls.Button;

import org.puremvc.as3.multicore.interfaces.INotification;
import org.puremvc.as3.multicore.utilities.fabrication.components.FlexModule;
import org.puremvc.as3.multicore.utilities.fabrication.components.FlexModuleLoader;
import org.puremvc.as3.multicore.utilities.fabrication.patterns.mediator.FlexMediator;

public class ApplicationMediator extends FlexMediator 
{               
public static const NAME:String = "ApplicationMediator";        

public function ApplicationMediator(viewComponent:Main)
{
super(NAME, viewComponent);             
}

override public function onRegister():void
{
super.onRegister();

moduleLoader.router = this.applicationRouter;
moduleLoader.defaultRouteAddress = this.applicationAddress;

moduleLoader.url = "MyModule.swf";

var vm:FlexModuleLoader = new FlexModuleLoader();
}

/**
* view內所有的元件使用  reactTo<ComponentName + EventName> 註冊(Fabrication會自動解析,監聽)
*/
public function reactToSendBtnClick(event:MouseEvent):void
{
var module:FlexModule = FlexModule(moduleLoader.child);

//第四個參數決定傳送給誰,"*"為全部,過濾格式為 <Module name/ Module child instance name>
routeNotification(RouteConst.SHELL_MESSAGE, main.sendMsg.text, null, "MyModule/*" );
}       

public function reactToInfoBtnClick(event:MouseEvent):void
{
var msg:String = "";
var module:FlexModule = FlexModule(moduleLoader.child);

msg += "Main Name: " + this.applicationAddress.getClassName() + "\n";                  
msg += "Module Name: " + module.moduleAddress.getClassName();

Alert.show(msg);
}                                               

/**
* 將mediator感興趣的notification寫成 function,格式為:respondTo<NotificationName>
*/
public function respondToModuleMessage(note:INotification):void
{
main.sendMsg.text = note.getBody().toString();
}

/**
* 元件要設 get,使用reactionTo參照的元件,modifier要設為 public
*/             
public function get sendBtn():Button
{
return main.sendBtn;
}

public function get moduleLoader():FlexModuleLoader
{
return main.moduleLoader;
}

public function get infoBtn():Button
{
return main.infoBtn;
}

protected function get main():Main
{
return viewComponent as Main;
}
}
}

要接收RountNotification一樣用RespondTo來接收,跟Pipes的概念不太一樣,沒有獨立的溝通管道,而是直接整合成PureMVC通知架構,這樣也是有好有壞,有時會搞不清楚通知是來自Module還是自己

MyModuleMediator

package idv.gd.hellofabrication.modules.myModule.view
{
import flash.events.MouseEvent;

import idv.gd.hellofabrication.common.RouteConst;

import mx.controls.Button;

import org.puremvc.as3.multicore.interfaces.INotification;
import org.puremvc.as3.multicore.utilities.fabrication.patterns.mediator.FlexMediator;

public class MyModuleMediator extends FlexMediator
{               
public static const NAME:String = "ApplicationMediator";        

public function MyModuleMediator(viewComponent:MyModule)
{
super(NAME, viewComponent);             
}

public function respondToShellMessage(note:INotification):void
{
myModule.sendMsg.text = note.getBody().toString();
}

public function reactToSendBtnClick(event:MouseEvent):void
{
routeNotification(RouteConst.MODULE_MESSAGE, myModule.sendMsg.text, null, "*");
}       

protected function get myModule():MyModule
{
return viewComponent as MyModule;
}
                public function get sendBtn():Button
{
return myModule.sendBtn;
}
}
}

範例要加掛PureMVC MultiCore、Pipes跟Fabrication的library

原始檔下載:http://gwbasic12.googlepages.com/Practice_Fabriation.zip

Google code:http://code.google.com/p/fabrication/

Drunks Blog:CodeDrunks Blog



使用Mxml標籤撰寫PV3D

0 意見

先前在pv3d.org看到的寫法,的確蠻特殊的,不過教學不多,這樣的寫法只能說比較簡潔,由於底層不是Flex元件,所以Flex的功能幾乎都不能用...,有興趣的朋友還是可以看看

寫個小練習:


2009-04-06_202629.jpg

<?xml version="1.0" encoding="utf-8"?>
<view:BasicView 
xmlns:mx="http://www.adobe.com/2006/mxml" 
xmlns:view="org.papervision3d.view.*" 
xmlns:scenes="org.papervision3d.scenes.*" 
xmlns:primitives="org.papervision3d.objects.primitives.*" 
xmlns:materials="org.papervision3d.materials.*" 
opaqueBackground="#ffffff"

<mx:Script>
<![CDATA[
import org.papervision3d.core.math.Sphere3D;
override protected function onRenderTick(event:Event = null):void
{
super.onRenderTick(event);
mySphere.yaw(12);
}
]]>
</mx:Script>
<view:scene>
<scenes:Scene3D>
<scenes:objects>
<primitives:Plane id="myPlane"
x="0" y="70" z="-300"
rotationX="-90">
<primitives:material>
<materials:ColorMaterial 
fillColor="0xFF0000" />
</primitives:material>
</primitives:Plane>
<primitives:Sphere id="mySphere"
x="0" y="190" z="-300">
<primitives:material>
<materials:WireframeMaterial/>
</primitives:material>
</primitives:Sphere>
</scenes:objects>
</scenes:Scene3D>
</view:scene>
</view:BasicView>


Adobe 提供免費的 Flex Builder 3 Professional

0 意見

Adobe放出消息,只要能證明目前失業,就能在官網上下載免費的Flex 3,雖然只授權做學術用途,但由此可見Adobe想擴大佔有率的決心

https://freeriatools.adobe.com/learnflex/