搜尋文章

2013年6月12日 星期三

android-canvas set bitmap IllegalStateException error

最近在android上試做了一個畫筆的功能

然後要能把畫的圖片儲存跟讀取

讀取的方法我是用BitmapFactory.decodeFile把檔案圖片轉成bitmap

然後再把這個bitmap畫在canvas上,但時候遇到了一個error

錯誤訊息是這樣的

java.lang.IllegalStateException: Immutable bitmap passed to Canvas constructor

股溝了一下發現也有人遇到這樣的問題

其原因是被載入的bitmap是不可被改變的,所以也不能用來畫在canvas上

如果是把bitmap帶入canvas的建構涵式的話就會出現上面的錯誤訊息

但如果是用canvas.setBitmap()的話只會出現這樣的錯誤訊息

java.lang.IllegalStateException

這一點真的想要抱怨一下android,錯誤訊息劈哩啪啦列了一大堆

唯一看到有用的訊息就是這一串然後也講得不清不楚了

但我想錯誤的原因應該都是一樣的,都是不可改變bitmap

解決的方法是把載入的bitmpa在複製一份出來用就好了~

Canvas mCanvas ;
File bimapFile = new File("mmt\sdcard","pic.png");
Bitmap orgBitmap = BitmapFactory.decodeFile(bimapFile.getAbsolutePath());
Bitmap copyBitmap = orgBitmap.copy(Bitmap.Config.ARGB_8888, true);

//用建構帶入bitmap或是用setBitmap方法帶入都可以
mCanvas = new Canvas(copyBitmap)

//or
//mCanvas = new Canvas();
//mCanvas.setBitmap(copyBitmap)

2013年6月3日 星期一

starling-AssetManager使用方法

在starling 1.3版中多增加了許多功能其中一個就是AssetManager。

AssetManager顧名思義就是用來管理素材的class

這邊就來記錄一下要如何使用


1.用Embed素材加入Texture
//先Embed圖片
[Embed(source="assets/bg.jpg")]
public static const BG:Class;

//先實體化AssetManager
vra am:AssetManager = new AssetManager();

//再把圖片加入AssetManager中
//第一個參數是這個texture在AssetManager中所註冊的名字
//第二個參數當然就是要放進AssetManager的texture
am.addTexture("BG", Texture.fromBitmap(new BG()));


//要從AssetManager抓取texture使用的話就使用getTexture方法
//參數就帶當初註冊名字
am.getTexture("BG");

//另外如果想知道所有有註冊的texture的名字可以使用getTextureNames方法
//這個方法會列出所有註冊過的名字
am.getTextureNames();

已經註冊的名字是不能重複註冊的,不然會報Error。

add的方法除了addTexture外還有addSound、addTextureAtlas

其實使用的方法都大同小異只是差在要丟什麼類型素材而已。




2.用enqueue方法加入素材,enqueue方法可以一次塞很多參數進去

也就是一次可以載入很多素材,就像他的名字一樣用列隊的方式依序載入

素材,而且enqueue是很強大的,它除了可以使用檔案路徑之外還可以

使用靜態的類別,甚至是可以搜尋整個資料夾路徑並且分門別類的幫你

自動載入自動註冊(AIR),下面就繼續記錄用不同的參數類型來使用enqueue載入素材。




第一種方法使用路徑載入檔案,使用檔案路徑的方式載入素材時比較要注意的地方是

AssetManager會自動使用檔案的檔名來註冊,例如是載入assets/bg.jpg這個

路徑裡的圖片,就會用bg這個名字來註冊,所以要用getTexture()方法取texture時

也是要用這個名字。

//一樣還是先實體化AssetManager
var am:AssetManager = new AssetManager();


am.enqueue("assets/bg.jpg");

//也可以一次給很多路徑中間用逗號格開就好
am.enqueue("assets/1.jpg","assets/2.jpg","assets/3.jpg");



第二種方法使用靜態類別載入,下面有一個用來embed檔案的靜態類別
package src.embed
{
 /**
  * ...
  * @author kuro
  */
 public class EmbedAsset 
 {
   
   //textureAtlas的圖片
   [Embed(source = "assets/lee.png")]
   public static const lee:Class;
   //textureAtlas的xml
   [Embed(source = "assets/leeXml.xml" , mimeType = "application/octet-stream")]
   public static const LeeAtlasXml:Class;
   
   //圖片
   [Embed(source="assets/bg.jpg")]
   public static const BGG:Class;
   
   //聲音
   [Embed(source="assets/yours.mp3")]
   public static const bgSound:Class;
   
   //字型
   [Embed(source="assets/font.png")]
   public static const font:Class
   [Embed(source="assets/font.fnt", mimeType="application/octet-stream")]
   public static const FontXml:Class
 }

}


使用靜態類別當作素材來源時要注意的地方是,AssetManager是用class名稱來註冊的

當要embed動畫所需要的textureAtlas素材的時候要注意一件事那就是

textureAtlas素材的圖片名稱跟embed的class名稱要一樣

但xml的名稱就不一定要跟embed的class名稱一樣了。


如果有去看過原始碼的話,就會發現AssetManager是先把class的lee先註冊到了

texture的Dictionary裡,之後載入textureAtlas的xml之後發現被註冊到

texture的Dictionary裡的lee是作為textureAAtlas需要的素材,所以就把

texture的Dictionary裡的lee移除掉,然後重新用lee這個名字去textureAAtlas的

Dictionary裡註冊,所以當textureAtlas註冊名字之後,你用getTexture()方法去

找lee的這個texture是找不到的,你只能用lee這個名字並且使用getTextureAtlas()這個方法

找到已經加入的textureAtlas素材。

//使用的話就這樣使用
var am:AssetManager = new AssetManager();

am.enqueue(EmbedAsset);

var lee:MovieClip = new MovieClip(mAssetManager.getTextureAtlas("lee").getTextures("lee_idle"), 24);
Starling.juggler.add(lee);
addChild(lee);


剛剛有說了註冊的名字是使用class名稱,所以如果是用靜態類別載入素材的話

要取得bg.jpg這張圖片就要用BGG的這個名稱。


如果是要取得聲音的話

可以用AssetManger裡的playSound("註冊的名字")取得聲音並且播放

playSound方法是會返回一個soundChannel,在呼叫這個方法時還可以帶

有關soundChannel的參數給他可給可不可。



如果是字型的話AssetManager會自動註冊字型到textField裡面,不用再呼叫

TextField.registerBitmapFont()註冊字型,而且也沒有方法可以抓取

載入進來的bitmapFont圖片,另外跟textureAtlas比較不一樣的地方是

要使用的時候不是用class的名稱,是要用這個字型的名稱,那字型的名稱

要去哪裡找呢?請把.fnt的這個檔案打開,其實裡面也是xml的結構

在第二行的地方會看到face="Brisk",這個face的地方就是字型的名稱

所以就要用Brisk這個名字,下面是使用方法

var text:TextField = new TextField(700, 100, "", "Brisk", 50, 0x000000, false);
   
text.hAlign = HAlign.LEFT;
text.text = "This is Bitmap Font Generator Test !";
addChild(text);

再來就是要講使用AIR在行動裝置上時要怎麼AssetManager

用AIR的話第一個還是可以使用上面所說的靜態類別的方法因為

那是把素材內嵌至swf裡比較沒有路徑的問題,但如果沒有要用embed的話

可以先把素材一起放在app的資料夾底下需要的時候在叫來用就好了

那要怎麼把宿才放在app資料夾底下呢?這邊我是用flash cs6所以我就來

講一下怎麼做。

第一步:選取檔案/android設定(如果是ios的話就是ios設定)

第二步:會看到下面有一個包含的檔案,然後會有三顆按鈕分別是

加入檔案、刪除檔案、加入資料夾,如果是只有幾個檔案的話可以

選擇加入檔案,但如果是有很多素材在同一個資料夾裡的話就可以選

加入資料夾,這樣這個資料夾裡的素材就都會被加入了

加入了檔案之後就要來看程式要怎麼寫了
//使用File類別,然後用applicationDirectory的屬性取得app根目錄
var appDir:File = File.applicationDirectory;

//之後再使用File的resolvePath()方法取得相對路徑
//如果是直接寫檔案路徑的話就會找到app/assets/bg.jpg;
am.enqueue(appDir.resolvePath("assets/bg.jpg"));

//這邊也可以直接寫資料夾名稱,AssetManager會自動搜尋可以用的
//全部素材並且載入註冊,非常的方便
am.enqueue(appDir.resolvePath("assets"))

再來講一下如何抓取檔案讀取的進度,AssetManager裡有一個loadQueue()

這也是呼叫AssetManager開始異步載入列隊裡的素材,這個方法必須帶一個function

給他,以便AssetManager callBack回來載入的進度

mAssetManager.loadQueue(onProgress);

private function onProgress(number:Number):void {
 var percent:int = Math.round(number * 100);
 trace("progress = " + percent + " %");
 if (number == 1) {
      (mStarling.root as Game).start(am);
 }
}



另外AssetManager 也可以載入網路上的資源下來,就把路徑換成http路徑就好了

還有載入的方法可以混著用類似像是下面這樣

//可以同時擺路徑也可以擺靜態類別
am.enqueue("asset/bg,jpg",EmbedAsset);

有關AsetManager的document可以來這邊看

AssetManager

2013/07/17更新

後來又自己鬼打牆遇到了一些問題,就再來記錄一下

1.用enqueue()放入要載入的檔案後,要記的要用loadQueue()載入檔案阿 !
就算沒有要知道載入進度也是一樣

2.在air的時候如果要用enqueue()掃資料夾的檔案的時候
要記得資料夾要跟fla檔案放在一起(用flash ide編譯的話)
這樣用appDir.resolvePath("assets")才會找的到檔案
千萬不要放在不同層,因為就算在路徑上加上../
air應用程式在找的時候也是從app路徑下開始找
所以還是找不到


2013年5月12日 星期日

unity3d-利用Command line開啟exe執行檔並傳值

上次有說過如果要使unity執行檔不要產生log檔或是要用popwindow的方式開啟


就要在程式命令集後面加上-nolog或是-popupwindow

關於有什麼參數可以使用可以參考下面連結


不過如果想要自訂義要傳給執行檔的參數的話該怎麼做呢?

其實還是跟上面一樣只要在.exe的後面加上參數就可以了

記得每個參數之間要以空白作為間隔

例如:c:\game\myGame.exe aa bb cc 123

之後在程式加上


var arguments : String[] = System.Environment.GetCommandLineArgs();


就可以抓到需要的參數了。

下面是log出來的結果

arguments[0] = c:\game\myGame.exe
arguments[1] = aa
arguments[2] = bb
arguments[3] = cc
arguments[4] = 123


2013年5月7日 星期二

Starling 相關資料

什麼是Starling?

以下是簡體中文官方的解釋


Starling是一个ActionScript类库,它模仿了传统的Flash显示列表。然而,和传统的显示对象不

同,Starling对象完全存在于Stage3D环境。这意味着,所有的显示对象都直接由GPU渲染,这

会带来非常明显的性能提升。

Starling并不是直接1:1的复制Flash API。所有的类都针对GPU模式进行了精简和优化。Starling向

开发者隐藏了Stage3D的内部细节,但如果您想创建自定义显示对象,也可以很容易访问到它

们。

就像它在iOS平台的姐妹框架,Sparrow Framework, Starling的设计宗旨是尽可能轻量级,易

于使用。作为一个开源项目,我们非常小心,保证代码易于阅读,理解和扩展

簡單的一句話來講就是

基於GPU加速的2D Flash API,使用Stage3D的宣染技術使

2D圖像能夠展現更好更快的效能,尤其是在行動裝置上更

有明顯的效果。

starling還有個好處是他可以跟許多的framework作結合,不管是物理引擎的Box2d、Nap

或是3D引擎的away3d、alternative3d都能透過starling使其效能更為提升


下面列一些有關Starling的學習資料,及基於Starling所擴展出來的framework

1.Starling英文官網

2.Starling中文站

這個網站就有點像官方英文的中文網站,由很多好心的人翻譯的,裡面有很多學習的資料

連document都有中文翻譯不過也是簡體的,裡面還有很多範例可以學習,建議一開始學習

starling的人可以先去這邊晃一圈就會對starling有個大概的了解。

3.hungry hero game

使用Starling所作的橫向捲軸遊戲,有發佈成網頁版及IOS版,最好的是他有公佈所有的

source code,學完這個大部分starling的功能都會知道怎麼用了

4.Hungry Hero Game Video Tutorials

除了公布了source之外還提供了影片教學,教你一步步熟習starling framework,不過主講人是

印度人,那個恐怖的口音實在讓我有點‧‧‧‧‧‧‧

5.Feathers

基於starling的UI類別,有很多在行動裝置上會用的UI及組件,讓這些UI透過starling的宣染

可以在行動裝置上讓用戶有更好的使用體驗。

6.Starling-Extension-Particle-System

starling的粒子特效,裡面還有介紹線上的粒子系統編輯器,以及在Mac上使用的編輯器

7.citrus Engine(2、3D橫向捲軸遊戲引擎)

結合Starling+away3d+box2d + Nape + awayPhysics的遊戲引擎

8.Dragon Bones

Dragon Bones是flash 2d的骨架動畫,使用Flasg製作素材後,再透過Dragon Bones的Flash IDE

的擴充套件來完成骨架動畫,其好處是能比用spriteSheets還要少的圖像完成複雜的骨架動畫

當然也支持starling
。作为
访问到

2013年5月6日 星期一

Starling-用setTexCoords-位移圖片UV

Starling-用setTexCoords-製做無接縫延伸背景圖這篇實現了無接縫的拼接背景

現在要再多一點變化讓背景圖片可以作無限的延伸,圖片一樣是拿那隻鳥來素材


一樣先把無接縫拼貼的部分先完成

//原圖為256*256,因為要讓圖片小一點所以設置作後一個參數2,使圖片縮小為原尺寸的1/2,BirdClass為Embed的圖片Class
var birdTexure:Texture = Texture.fromBitmap(new BirdClass(), true, false, 2);
//設置Texture為重複
birdTex.repeat = true;
var birdBackground:Image = new Image(birdTex);
//把Image的寬和高設置為跟螢幕一樣大
birdBackground.width = this.stage.stageWidth;
birdBackground.height = this.stage.stageHeight;
//橫向重複數量
var horizontalSize:int = 8;
//直向重複數量
var verticalSize:int = 8
 
birdBackground.setTexCoords(1, new Point(horizontalSize, 0));
birdBackground.setTexCoords(2, new Point(0, verticalSize));
birdBackground.setTexCoords(3, new Point(horizontalSize, verticalSize));
addChild(birdBackground);

之後在加上兩個全域變數

private var bird:Image;
//紀錄滑鼠作標位置
private var mMousePos:Point = new Point();

以及enterFrame跟Touch事件的監聽

addEventListener(Event.ENTER_FRAME, loop);
addEventListener(TouchEvent.TOUCH, onTouch)


 private function onTouch(event:TouchEvent):void
 {
        //這裡用滑鼠的全域作標-圖片的一半寬和一半高是為了讓滑鼠坐標以圖片中心當(0,0)的位置           
         mMousePos.x = event.getTouch(this).globalX - ( this.stage.stageWidth >> 1);
           mMousePos.y = event.getTouch(this).globalY - (this.stage.stageHeight >> 1);
      
}
  
private function loop(e:Event):void 
{
       //迴圈跑UV的四個頂點
        for (var i:int = 0; i < 4; i++) {
           //用getTexCoords方法取得每個UV點的Point
           var p:Point = bird.getTexCoords(i);
           //在改變每個UV點的位置的X、Y
           p.x += mMousePos.x * .00002
           p.y += mMousePos.y * .00002
           //最後用setTexCoords方法設置圖片的頂點以及坐標位置
            bird.setTexCoords(i, p);
       }


}
這樣移動滑鼠時就會看到圖片會跟著滑鼠的移動無限制的延伸背景




參考資料
Best way to do a scroll background

http://www.cnblogs.com/sevenyuan/archive/2013/01/22/2871634.html

Starling框架——UV坐标控制纹理贴图滚动

UV Scrolling in Starling


Starling中实现形状不规则的卷轴地图滚动

2013年4月26日 星期五

Starling-用setTexCoords-製做無接縫延伸背景圖

在上一篇Starling-用setTexCoords-裁切圖片中有講到了一些UV坐標的概念

這次要繼續使用Image的setTexCoords的方法來產生無接縫延伸背景圖

這邊先分享一個線上製做無接縫圖片的地方


這邊有很多現成的素材可以下載,另外也可以利用他線上的編輯器去編輯

素材的顏色等等 . . .

之後就可以下載png圖檔下來,下載png是不用付費的,功能很簡單應該

就不用再另外教學了,隨便摸一摸應該就會了

無接縫的素材做好了後就可以把素材Embed到程式了

不過我這邊先不用無接縫的素材,因為如果用了就看不出來到底拼接了幾個出來了

為了好了解我這邊還是先用上個範例的鳥~

程式碼如下



//原圖為256*256,因為要讓圖片小一點所以設置作後一個參數2,使圖片縮小為原尺寸的1/2,BirdClass為Embed的圖片Class
var birdTexure:Texture = Texture.fromBitmap(new BirdClass(), true, false, 2);
//設置Texture為重複
birdTex.repeat = true;
var birdBackground:Image = new Image(birdTex);
//把Image的寬和高設置為跟螢幕一樣大
birdBackground.width = this.stage.stageWidth;
birdBackground.height = this.stage.stageHeight;
//橫向重複數量
var horizontalSize:int = 8;
//直向重複數量
var verticalSize:int = 8

birdBackground.setTexCoords(1, new Point(horizontalSize, 0));
birdBackground.setTexCoords(2, new Point(0, verticalSize));
birdBackground.setTexCoords(3, new Point(horizontalSize, verticalSize));
addChild(birdBackground);

這邊其實我也不是很懂其原理,只知道這樣做可以達到無接縫拼貼的效果

當然每個位置的的值也不一定要像我上面寫的一樣,自己可以隨便填個值看看效果

也許會產生出很奇特的形狀貼圖

Starling-用setTexCoords-裁切圖片

在starling的教學範例Hungry Hero裡,遊戲下方的街景以及遊戲背景的滾動方式是用

兩張圖片不斷的輪流交替來產生背景滾動的效果,不過要滾動背景的話其實還有

另一種方式是改變圖片的頂點位置以及紋理的UV坐標,在starling中預設的DisplayObject

都是四邊形,圖形的UV作標點分別為下圖所示

0  ─ ─ ─ 1
│            │
│            │
│            │
2  ─ ─ ─ 3

設置頂點位置以及紋理的UV坐標可以達到許多效果,例如上述所說的滾動視圖達到

橫向捲軸遊戲裡的無限延伸背景的效果,另外也可以拿來作裁切圖片和無接縫圖片的

背景延伸等等等 . . . .下面就來示範一下怎麼分別達成這些效果

1.裁切圖片
下面這邊有一張圖


















如果要裁切這張圖片的右下角1/4的圖的話要怎麼做呢?

我們可以用Image裡的setTexCoords方法裁切


var image:Image = new Image(texture);
addChild(image);
var point:Point = new Point();

//第一個點
point.x = 0.5;
point.y = 0.5;
image.setTexCoords(0, point);

//第二個點
point.x = 1;
point.y = 0.5;
image.setTexCoords(1, point);

//第三個點
point.x = 0.5;
point.y = 1;
image.setTexCoords(2, point);

//第四個點
point.x =1;
point.y = 1;
image.setTexCoords(3, point);

解釋一下上面程式碼的意思

假設圖片的四邊長分別都為1

那要裁切圖片的1/4右下角的話

第一個點當然是圖片的正中心拉

假設圖片的四邊長分別都為1

最左上角坐標為(0,0),右上角坐標為(1,0),左下角坐標為(0,1),右下角坐標為(1,1),


那要裁切圖片的1/4右下角的話第一個點當然是圖片的正中心拉


所以會看到第一個點是設在(0.5,0.5)的位置上,第二個點就會在(1,0.5)


以此類推就會推出上面所設的座標位置拉


裁切出來之後你應該會發現裁切出來的部分被放大成原圖片的大小,以上圖為例

圖片為256*256裁切出來的右下角應該要是128*128,可是卻被放大為256*256了

因此會變得有點模糊,所以如果要裁切後不被放大的話就手動把圖片縮回來就好了

image.width = image.width >> 1;
image.height = image.height >> 1;

//
設置