顯示具有 Flash 標籤的文章。 顯示所有文章
顯示具有 Flash 標籤的文章。 顯示所有文章

2013-05-27

以 Flash/AIR/Starling 測試開發 iOS App for iPhone5 的怪現象

※ 2013-05-31 請看 Starling 官方多解析度螢幕的開發指引, 此篇可以略過了 !!!

或許不是怪現象,可能是最近太少寫 Flash/AS3...

為了在 iPhone 5 可以 640*1136 顯示,放了張啟動用圖 Default-568h@2x.png ( 參考 Deploying AIR Apps on iPhone 5 )。AIR SDK 3.7 和 3.8 beta 情況相同。

AIR for iOS settings,設定:

Aspect Ratio: Landscape (橫向)
  勾選 Full screen
  勾選 Auto orientation
Resolution: High

stage (場景) 設定不同時就有怪怪的情況:

stage: 1136*640, FPS:60 -> 一開始執行就卡住
stage: 1136*640, FPS:30 -> 開始幾個畫面位置大跑位,後面的畫面卻正常
stage: 568*320, FPS:30 -> 正常


明明就已經 Full screen 了啊, 花熱發... Orz

2013-05-27 更新 ------------------------------------
應該在判斷是 iOS 後, 使用 Capabilities.screenResolutionX 和 screenResolutionY。

在 document class 放 stage 的 resize 偵聽器發現 ( resolution 設為 high ),一開始 stage 的大小會被調整為原來 stage 大小的兩倍,之後 ( 約 1~ 2 sec ) 會被調整成 screen 大小。這就可以解釋之前的現象了。

2012-11-11

Flash 開發效能檢測工具: TheMiner

一般常使用 Hi-ReS-Stats 來檢測 Flash 的效能, 可以看到簡單的 FPS 的記憶體使用情況。

剛剛無意間發現 TheMiner (舊名為 FlashPreloadProfiler), 試用了「非商業版」, 功能不少, 感覺還不錯。有非商業版就表示有商業版, 請自行閱讀其使用者條款 (有些功能商業版才提供)。


作者的 Blog 介紹: http://jpauclair.net/flashpreloadprofiler/
官網: http://www.sociodox.com/theminer/
安裝方式: http://www.sociodox.com/theminer/tutorial/tutorial_install.html

安裝方式建議使用第三種, 步驟:
1. 設定允許 TheMiner_zh-tw.swf 的全域安全性 (Flash Global Security Settings)
2. 在用戶家目錄設定 mm.cfg 檔, 在 Win 7 上的設定情況
PreloadSWF=PreloadSWF=C:\Users\用戶名稱\TheMiner_zh-tw.swf

在 Flash IDE 測試影片時, 就可以看到左上方的工具列了。

2012-07-19

Publishing APK for Android with ANE included by using Flash CS6

Select Menu: "File > Publish Settings > ActionScript Settings"
Select Tab: "Library path"
Click icon button: "Add New Path"
Click icon button: "Browse to a Native Extension (ANE) file"

After browsing and selecting an ANE file, the file will be added in included files ( Checking "General" tab in "AIR for Android Settings"  ).

Publishing APK by using "AIR for Android Settings" panel, the ANE will be added in the APK file.

2010-08-18

Flash 可以透過 JavaScript 取得 Facebook 的 session

Flash 可以透過 ExternalInterface (JavaScript) 取得 Facebook 的 session,
只要取得 session 裡的 access_token 就可以在 Flash 呼叫 Facebook 的 Graph API。

以下程式碼的要點:
1. 使用 swfobject 顯示 Flash 內容。
2. JavaScript 都載入後再顯示 Flash。
3. Flash 先呼叫 JS function,JS function 呼叫 FB function,callback function 呼叫 Flash function。
4. JS function 裡,swf movie name 和 callback function name 以傳入的方式設定。
5. access_token 以 get 方式傳送。
6. Graph API 回傳的內容是格式化過的 JSON 字串。
Code 參考

2010-06-22

用 AIR2 透過 DatagramSocket (UDP) 及截圖做簡陋的監視服務

安裝 PicServer.air 的電腦必須要有 Webcam,當然也要有網路功能,使用 port 24688,啟動後會等待 client 登入。安裝 PicClient.air 的電腦是監看端,使用 port 24689,記得防火牆要讓訊息通過才行。由於使用 UDP,所以無法得知連線狀態,因為 client 必須傳 session 給 server,server 才會傳畫面資料給 client。client 端還可以發展成調整時間間隔、畫面品質、及存檔等。
原始碼如下(請使用 Flash CS5)。

2010-04-24

Ajax Animator

Ajax Animator 是個動畫編輯器, 顧名思義是用 Ajax 做的, 能用 JavaScript 做到這樣實在不容易~
這種東西才能在 iPad 上跑 :P
它也可以利用後台技術和 Flex SDK (或 MING ) 生成 SWF
其它非官方、開源、免費工具請參考 Open Source and free Development Tools for Flash

2010-04-23

Flash CS5 支援的 XFL 格式


XFL 的簡單介紹
XFL - eXtensible Form Language Format first

XFL 算是蠻新的格式, 在 Flash CS4 時就支援了, 但 CS4 只能開不能存或滙出。我用 CS5 beta 存 XFL,但在 CS4 卻沒辦法開,應該是格式有更新過。


CS4 時 After Effects 可以滙出,再用 Flash 開

下面這篇說明 XFL 的功能以及為什麼 Flypaper 很快就支援了

重點來了,XFL 是 XML 格式不是 Binary 格式,Spec一定會公開,支援編輯、轉換的軟體也會變多,如此一來 Flash <-> HTML5 中間的隔閡是越來越小。Flash: Die-hard
:D

2010-04-16

MDM ZINC 3 雜記

最近使用 MDM ZINC 3 的雜記:
  1. 使用 AS2 時,SWF 發佈的版本必須為 for Flash Player 8 (含) 以下。
  2. AS2 類別檔使用到 mdm 時,宣告為 dynamic。
  3. AS3 Flash document class 一定要在 constructor 內呼叫 domdm.Application.init()。
  4. 載入其它 SWF 時,記得在主要的 Flash Movie 的最前面下 mdm.Flash.setSWFDir()。
  5. SQLite 無法存放中文,可以用 URL-encoded 解決(mdm 存入時不會自動轉換為 UTF-8)。
  6. SQLite 開啟資料庫時,檔案會自動建立。
  7. SQLite 判斷資料表是否存在用 "SELECT * FROM sqlite_master WHERE type='table' AND name='DB_TABLE'"。
  8. Firefox 的附加元件 SQLite Manager 相當好用。
  9. 中文輸入有問題,會變亂碼。

2010-04-12

Flash AS3 翻頁、翻書效果

這是個被問到爛的效果, 不過難得有 open source 又是 ActionScript 3 的版本
http://megazine.mightypirates.de/
使用前還是請看一下說明文件。

2010-03-26

Flash Builder 4 寫 Facebook Apps

Adobe Developer Center 上 Jeanette Stallons 的兩篇 Quick Start 是必看的文章:Build and test locallyDeploy on Facebook。熱騰騰的 Flash Builder 4 當然要好好利用一下 :D

Step 1: 先要有網站空間,使用免費的也行。設定一個空目錄,如:「http://www.riarock.net/fbapps/fbastutorial/」給 Facebook App 使用。

Step 2: 登入 Facebook 並在「http://www.facebook.com/developers/」建立新的應用程式。其中必填的項目為:
基本資料→應用程式名稱 :: 就是應用程式名稱,不能用 Face、FB 等混淆視聽的字眼,所以在此用了 Footbook。
畫布→畫布頁面網址 :: 如「http://apps.facebook.com/fbastutorial/」。
畫布→Canvas Callback URL :: 在這個例子設定為「http://www.riarock.net/fbapps/fbastutorial/」。
畫布→呈現方法 :: 設定使用「Iframe」。
聯外通→聯外通網址 :: 在這個例子設定為「http://www.riarock.net/fbapps/fbastutorial/」。
進階→沙盒模式 :: 測試時先設定為「啟用」。

Step 3: 安裝好 Flash Builder 4 之後,開一個新專案,命名為 fbastutorial。將 Facebook_library_v3.4_flex.swc 放到專案的 libs 目錄。 預設的 Application 為 fbastutorial.mxml,不寫程式,直接執行。

Step 4: 將產生的 bin-debug/fbastutorial.html 複製到 src/index.html。並在指定的位置增加下面標起來的程式碼,用來取得 Facebook 給的 GET 參數。
var flashvars = {}; // ← 找到這一行,增加下面的程式碼
// *** START 增加的部份 ***
var strHref = window.location.href;
if ( strHref.indexOf("?") > -1 ) {
var strQueryString = strHref.substr(strHref.indexOf("?")+1);
var aQueryString = strQueryString.split("&");
for ( var iParam = 0; iParam < aQueryString.length; iParam++ ) {
var aParam = aQueryString[iParam].split("=");
flashvars[aParam[0]] = aParam[1];
}
}
// *** END 增加的部份 ***

Step 5: fbastutorial.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" minWidth="840" minHeight="500"
applicationComplete="init()"
viewSourceURL="srcview/index.html">
<!-- *** 注意:這裡是用 applicationComplete,不是用 creationComplete *** -->

<fx:Script>
<![CDATA[
import com.facebook.Facebook;
import com.facebook.commands.friends.GetFriends;
import com.facebook.commands.users.GetInfo;
import com.facebook.data.friends.FriendsCollection;
import com.facebook.data.friends.GetFriendsData;
import com.facebook.data.users.FacebookUser;
import com.facebook.data.users.FacebookUserCollection;
import com.facebook.data.users.GetInfoData;
import com.facebook.events.FacebookEvent;
import com.facebook.net.FacebookCall;
import com.facebook.utils.FacebookSessionUtil;

import mx.controls.Image;

private var session:FacebookSessionUtil
private var facebook:Facebook;
private var fbUser:FacebookUser;
private var dictionary:Dictionary;

private function init():void {
// *** 一開始測試時可以先填入 API Key 和 Application Secret
//session = new FacebookSessionUtil("<API Key>", "<Application Secret>", loaderInfo);
session = new FacebookSessionUtil(loaderInfo.parameters.fb_sig_api_key, null, loaderInfo);
// 取得 Facebook Session,有 Session 才有權使用 Facebook API
facebook = session.facebook;
// 取得 Facebook Session 並連結之後,呼叫 onSessionConnect 方法
session.addEventListener(FacebookEvent.CONNECT, onSessionConnect);

if(loaderInfo.parameters.fb_sig_added == true){
// 有登入時,呼叫核對 Session,OK的話發出 CONNECT 事件
session.verifySession();
} else if(loaderInfo.parameters.fb_sig_added == false){
// 沒登入時
navigateToURL(new URLRequest("http://www.facebook.com/login.php?api_key="+loaderInfo.parameters.fb_sig_api_key),"_top");
} else {
// 沒取得資料時
session.login();
btnLogin.visible = true;
}
}

private function onSessionConnect(event:FacebookEvent):void {
// 呼叫取得朋友資料
var call:FacebookCall = facebook.post( new GetFriends() );
// 取得朋友資料之後,執行 onGetFriendsComplete
call.addEventListener(FacebookEvent.COMPLETE, onGetFriendsComplete);
}

private function onGetFriendsComplete(event:FacebookEvent):void {
// 呼叫時用 GetFriends,取得時用 GetFriendsData
var friendsData:GetFriendsData = event.data as GetFriendsData;
var friends:FacebookUserCollection = friendsData.friends;
// 將朋友的 ID 放入 uids 陣列
var uids:Array = [];
for(var i:int=0; i< friends.length; i++) {
var f:FacebookUser = friends.getItemAt(i) as FacebookUser;
uids.push(f.uid);
}
// GetFriends 只能取得朋友的 uid,必須呼叫 GetInfo 才能取得朋友資料
var call:FacebookCall = facebook.post(
// 設定要取得的資料項
new GetInfo(uids, ["name", "pic_square"])
);
call.addEventListener(FacebookEvent.COMPLETE, onGetFriendsAttr);
}

private function onGetFriendsAttr(event:FacebookEvent):void {
// 呼叫時用 GetInfo,取得時用 GetInfoData
var getInfoData:GetInfoData = event.data as GetInfoData;
var userCollection:FacebookUserCollection = getInfoData.userCollection;
dictionary = new Dictionary();
// 一一取出朋友資料
for(var i:int=0; i<userCollection.length; i++) {
var usr:FacebookUser = userCollection.getItemAt(i) as FacebookUser;
var img:Image = new Image();
// 沒有大頭貼時用預設的圖
if(! usr.pic_square) {
img.source = 'http://static.ak.fbcdn.net/pics/q_silhouette.gif';
} else {
img.source = usr.pic_square;
}
img.toolTip = usr.name;
img.buttonMode = true;
// 使用字典以方便用物件取得字串
dictionary[img] = usr.uid;
img.addEventListener(MouseEvent.CLICK,onImageClick);
tilesPic.addElement( img );
}
}
private function onImageClick(event:MouseEvent):void {
var img:Image = event.currentTarget as Image;
navigateToURL(new URLRequest("http://www.facebook.com/profile.php?id="+dictionary[img]),"_blank");
}
]]>
</fx:Script>

<s:Button x="10" y="10" label="點按登入 Facebook" id="btnLogin"
visible="false" click="session.validateLogin()"/>
<s:Scroller x="30" y="30" width="800" height="450">
<s:TileGroup width="100%" height="100%" clipAndEnableScrolling="true" id="tilesPic">
</s:TileGroup>
</s:Scroller>

</s:Application>

Step 6: 發佈,上傳至「http://www.riarock.net/fbapps/fbastutorial/」測試。

Step 7: 範例在「http://apps.facebook.com/fbastutorial/」,於 swf 上按右鍵選「View Source」就可以看到原始檔,並下載專案檔了。

新作:FLASH+PHP資料庫網站開發設計

個人新作「FLASH+PHP資料庫網站開發設計」出版了,感謝舊雨新知的支持!

個人新作「FLASH+PHP資料庫網站開發設計」出版
試讀「第6章」18頁

出版公司書籍介紹
博客來
金石堂
建議:老話一句,一本書是無法滿足所有人需求的,請先到實體書店翻閱,符合需求再購買!

2010-02-22

Video 保護

目前 FLV 的保護主要由 FMS 下手, 但是用 FMS 有諸多缺點。
Adobe AIR 2 將提供 DRM 的功能, 但是需搭配 Flash Access 2 使用。依據之前的經驗, Flash Access 2 應該不會便宜到哪去, 而且 Video 的傳輸頻寬也是問題。

在簡單保護方面(防外行), NetConnection 和 NetStream 實在包的太「好」了, 沒有下手的空隙。如果使用 AIR 2, 可以用 ServerSocket 弄個 HTTP Server 來傳 Video 資料。這個時候, Video 就可以編碼(隨君高興)存成檔案, 在 Server 讀資料送出時, 可以自行解碼, 再送給 Client。這樣做的缺點是效能會略差, 而且要想辦法藏好解碼的 KEY(可以透過登入機制再拐個彎, 有心要找的人還是可以找到)。

2009-12-23

Flash取得Cookie

當然還是得透過 JavaScript 才會取得, 不過可以偷懶不用寫 JavaScript:

var s:String = ExternalInterface.call("document.cookie.toString");

通常會處理一下

var cookieStr:String = ExternalInterface.call("document.cookie.toString");
var cookieObj:Object = {};
cookieStr = cookieStr.split(' ').join('');
var tmp:Array = cookieStr.split(';');
for(var i in tmp) {
var tmp2:Array = tmp[i].split('=');
cookieObj[tmp2[0]] = unescape(tmp2[1]);
}
s_txt.text = cookieObj['PHPSESSID'];

2008-06-24

動態改變 Flash Movie 的大小

原始網頁: BrowserCanvas. The World’s Easiest Way to Dynamically Resize Flash

2008-06-06

以動態文字作為遮罩

mmug上討論的問題
在此我用之前的 Substitute 類別來解決

Frame Actions:
// 底
var bmd:BitmapData = new BitmapData(200, 200, true, 0xFFCCCCCC);
var seed:int = int(Math.random() * int.MAX_VALUE);
var channels:uint = BitmapDataChannel.RED | BitmapDataChannel.BLUE;
bmd.perlinNoise(100, 80, 12, seed, false, true, channels, false, null);
var bm:Bitmap = new Bitmap(bmd);
this.addChild(bm);

// 動態文字
var _txt:TextField = new TextField;
_txt.autoSize = "left";
var myTextFormat:TextFormat = new TextFormat(null, 30, 0, true);
_txt.text = "動態文字";
_txt.x = 50;
_txt.setTextFormat(myTextFormat);
this.addChild(_txt);

// 建立替身
import lin.shinder.display.Substitute;
var s:Substitute = new Substitute(_txt).displace();
s.rotation = 30;

// 設定遮罩
bm.cacheAsBitmap = true;
s.cacheAsBitmap = true;
bm.mask = s;

原始檔下載

2008-06-05

取得 Domain Name (AS3 版)

/**
* author: shinder lin
* email: shinder.lin@gmail.com
*/
package lin.shinder.net
{
import flash.display.DisplayObject;
public class HttpDomain
{
static public var defaultDomain:String = "http://localhost";
static public function getDomain(displayObj:DisplayObject)
{
var url_str:String = displayObj['stage'].loaderInfo.loaderURL;
if (url_str.indexOf("http://") == 0 || url_str.indexOf("https://") == 0) {
var s_index:int = url_str.indexOf("/", 10);
return url_str.substring(0, s_index);
} else {
return defaultDomain;
}
}
}
}

由 URL 取得 Domain Name (AS2 版)

2008-06-04

PHP 使用 JSON 和 AS3 溝通

JSON 常用在 AJAX 的資料交換上,其實也可以用在 SWF<->PHP 上。
PHP5有內建 JSON 的函式;PHP4沒有,但可以用 PEAR 的 JSON 類別
AS3 則可以用 as3corelib 裡的 JSON 類別。
以下是將DB資料轉換成JSON的例子。
mysql2json4.php
/*** shinder.lin@gmail.com
for PHP4
*/
require_once("JSON.php");
function mysql2json4($sql) {
if(is_string($sql)) {
$query = mysql_query($query) or die(mysql_error());
} else {
$query = $sql;
}

$ar = array();
if($total = mysql_num_rows($query)) {
while($row = mysql_fetch_assoc($query)) {
$obj = array();
foreach($row as $key => $value) {
$obj[ $key ] = $value;
}
array_push($ar, $obj);
}
mysql_data_seek($query, 0);
}

$json = new Services_JSON();
return $json->encode($ar);
}
?>

test_mysql2json4.php
require("mysql2json4.php");

mysql_connect("localhost", "root", "");
mysql_select_db("test");
mysql_query("SET NAMES 'utf8'");
$q = mysql_query("select * from ctest");
echo mysql2json4($q);
?>

test_json.fla frame actions:
import  com.adobe.serialization.json.*;

var ur:URLRequest = new URLRequest("http://localhost/json_test/test_mysql2json4.php");
var ul:URLLoader = new URLLoader();
ul.addEventListener(Event.COMPLETE, onComplete);
ul.load(ur);

function onComplete(evt:Event) {
trace(ul.data);
var o:Object = JSON.decode(ul.data);
QopDump.echo(o);
}



資料傳給 PHP
test_json_insert4.php
require_once("JSON.php");

$raw = $GLOBALS["HTTP_RAW_POST_DATA"];

$json = new Services_JSON();
$ar = (array) $json->decode($raw);

mysql_connect("localhost", "root", "");

mysql_select_db("test");
mysql_query("SET NAMES 'utf8'");
// watch out for sql injection
$sql = sprintf("INSERT INTO `ctest` (`sno`, `name`, `phone`) VALUES (NULL, '%s', '%s')", $ar['name'], $ar['phone']);
echo (bool) mysql_query($sql);
?>

test_json_submit.fla frame actions:
import  com.adobe.serialization.json.*;

var ur:URLRequest = new URLRequest("http://localhost/json_test/test_json_insert4.php");
ur.method = URLRequestMethod.POST;
var ul:URLLoader = new URLLoader;

submit_btn.addEventListener(MouseEvent.CLICK, onSubmit);

function onSubmit(evt:MouseEvent):void {
var obj:Object = {name:name_ti.text, phone:phone_ti.text};
var str:String = JSON.encode(obj);
ur.data = str;
ur.contentType = "text/plain";
ul.load(ur);
// trace(str);
}

ul.addEventListener(Event.COMPLETE, onComplete);

function onComplete(evt:Event) {
info_ta.text = ul.data;
}

相關檔案下載

2008-05-20

建立 DisplayObject 物件 的 Bitmap 替身

包含動態文字的視覺物件常會因為旋轉而消失
在此弄個類別用以建立替身, 由於是點陣資料, 故縮放的時候會比較醜
測試的 Frame Actions :
import lin.shinder.display.Substitute;

var _txt:TextField = new TextField;
_txt.text = "ABCDEF";
this.addChild(_txt);

var s:Substitute = new Substitute(_txt).displace();
s.rotation = 30;

var s_mc:Substitute = new Substitute(t_mc);
s_mc.x = 200;
s_mc.y = 200;
this.addChild(s_mc);

類別檔 Substitute.as :
package lin.shinder.display
{
import flash.geom.Rectangle;
import flash.geom.Matrix;
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.display.PixelSnapping;
// 替身
dynamic public class Substitute extends Sprite
{
private var bitmap:Bitmap;
public var bitmapData:BitmapData;
public var original:DisplayObject;

public function Substitute(disp:DisplayObject)
{
original = disp;
bitmapData = new BitmapData(disp.width, disp.height, true, 0);
var rect:Rectangle = disp.getBounds(disp);
var matrix:Matrix = new Matrix;
matrix.translate(-rect.x, -rect.y);
bitmapData.draw(disp, matrix);
bitmap = new Bitmap(bitmapData, PixelSnapping.AUTO, true);
bitmap.x = rect.x;
bitmap.y = rect.y;
this.addChild(bitmap);
this.visible = original.visible;
this.x = original.x;
this.y = original.y;
this.scaleX = original.scaleX;
this.scaleY = original.scaleY;
this.rotation = original.rotation;
}

public function displace():Substitute
{
if(! original.parent) {
trace('The original DisplayObject is not in display chains !');
return null;
}
var _parent:DisplayObjectContainer = original.parent as DisplayObjectContainer;
var depth:int = _parent.getChildIndex(original);
_parent.addChildAt(this, depth);

_parent.removeChild(original);
return this;
}
}
}

測試範例原始檔

2008-05-16

Flash Player 10 beta, code-named "Astro"

新的 Flash Player 10 進入 beta 階段
Developer 另一階段的苦難又要開始了 :P

FB 留言