js pixi框架 極其詳細到位(入門)-----轉載
pixi是一個js 的輕量級的遊戲類庫框架,很適用於做H5的一些canvas動畫特效。
這篇文章是關於pixi的入門教程 ,裡面的講解非常的到位細緻,是我看到過的文章裡講解的算是最好的了。
去年快過年看的教程 ,今天再想看的時候發現沒找到,不過經過不懈的搜尋還是找到 ,那就趕緊給轉過來吧。
pixi(入門)
Pixi教程
基於官方教程翻譯;水平有限,如有錯誤歡迎提PR,轉載請註明出處。翻譯者為htkz(完成了用 Pixi 繪製幾何圖形 和 顯示文字 章節)和zainking(完成了其他所有章節) 另感謝htkz、NearZXH以及HHHHhgqcdxhg
這個教程將要一步步介紹怎麼用Pixi做遊戲或者互動式媒體。這個教程已經升級到 Pixi v4.5.5。如果你喜歡這個教程,你一定也喜歡這本書,它比這個教程多了80%的內容。
目錄:
- 介紹
- 安裝
- 建立舞臺(stage)和畫布(renderer)
- Pixi 精靈
- 把影象載入進紋理快取
- 顯示精靈(sprite)
- 定位精靈
- 大小和比例
- 角度
- 從精靈圖(雪碧圖)中獲取精靈
- 使用一個紋理貼圖集
- 載入紋理貼圖集
- 從一個紋理貼圖集建立精靈
- 移動精靈
- 使用速度屬性
- 遊戲狀態
- 鍵盤響應
- 將精靈分組
- 用 Pixi 繪製幾何圖形
- 顯示文字
- 碰撞檢測
- 例項學習: 寶物獵人
- 一些關於精靈的其他知識
- 展望未來
i.Hexi
ii.BabylonJS - 支援這個工程
介紹
Pixi是一個超快的2D渲染引擎。這意味著什麼呢?這意味著它會幫助你用JavaScript或者其他HTML5技術來顯示媒體,建立動畫或管理互動式影象,從而製作一個遊戲或應用。它擁有語義化的,簡潔的API介面並且加入了一些非常有用的特性。比如支援紋理貼圖集和為精靈(互動式影象)提供了一個簡單的動畫系統。它也提供了一個完備的場景圖,你可以在精靈圖層裡面建立另一個精靈,當然也可以讓精靈響應你的滑鼠或觸控事件。最重要的的是,Pixi沒有妨礙你的程式設計方式,你可以自己選擇使用多少它的功能,你可以遵循你自己的編碼風格,或讓Pixi與其他有用的框架無縫整合。
Pixi的API事實上比起久經沙場又老舊的Macromedia/Adobe Flash API要精緻。如果你是一個Flash開發者,將會對這樣的API感覺更好。其他的同類渲染框架(比如CreateJS,Starling, Sparrow 和 Apple’s SpriteKit.)也在使用類似的API。Pixi API的優勢在於它是通用的:它不是一個遊戲引擎。這是一個優勢,因為它給了你所有的自由去做任何你想做的事,甚至用它可以寫成你自己的遊戲引擎。(譯者:作者這點說的很對,譯者有一個朋友就使用它製作自己的Galgame引擎AVG.js)。
在這個教程裡,你將會明白怎樣用Pixi的強大的圖片渲染能力和場景圖技術來和做一個遊戲聯絡起來。但是Pixi不僅僅能做遊戲 —— 你能用這個技術去建立任何互動式媒體應用。這甚至意味著手機應用。
你在開始這個教程之前需要知道什麼呢?
你需要一個對於HTML和JavaScript大致的瞭解。你沒必要成為這方面的專家才能開始,即使一個野心勃勃的初學者也可以開始學習。這本書就是一個學習的好地方:
Foundation Game Design with HTML5 and JavaScript
我知道這本書是最好的,因為這本書是我寫的!
這裡有一些好的程式碼來幫助你開始:
Khan Academy: Computer Programming
選擇一個屬於你的最好的學習方式吧!
所以,明白了麼?
你知道JavaScript的變數,函式,陣列和物件怎麼使用麼?你知道JSON 資料檔案是什麼麼? 你用過 Canvas 繪圖 API麼?
為了使用Pixi,你也需要在你專案的根目錄執行一個web伺服器,你知道什麼是web伺服器,怎麼在你的專案資料夾裡面執行它麼?最好的方式是使用node.js 並且去用命令列安裝http-server. 無論如何,你需要習慣和Unix命令列一起工作。你可以在這個視訊中去學習怎樣使用 Unix當你完成時,繼續去學習 這個視訊.你應該學會怎樣用Unix,這是一個很有趣和簡單的和電腦互動的方式,並且僅僅需要兩個小時。
如果你真的不想用命令列的方式,就嘗試下 Mongoose webserver:
或者來使用Brackets text editor這個令人驚豔的程式碼編輯器。他會在你點選那個“閃電按鈕”的時候自動啟動web伺服器和瀏覽器。
現在,如果你覺得你準備好了了,開始吧!
(給讀者的小提示:這是一個 互動式的文件.如果你有關於特殊細節的任何問題或需要任何澄清都可以建立一個GitHub工程 issue ,我會對這個文件更新更多資訊。)
安裝
在你開始寫任何程式碼之前,給你的工程建立一個目錄,並且在根目錄下執行一個web伺服器。如果你不這麼做,Pixi不會工作的。
現在,你需要去安裝Pixi。
安裝 Pixi
這個教程使用的版本是 v4.5.5 你可以選擇使用 Pixi v4.5.5的釋出頁面pixi
資料夾下的pixi.min.js
檔案,或者從Pixi的主要釋出頁面中獲取最新版本。
這個檔案就是你使用Pixi唯一需要的檔案,你可以忽視所有這個工程的其他檔案,你不需要他們。
現在,建立一個基礎的HTML頁面,用一個<script>
標籤去載入你剛剛下載的pixi.min.js
檔案。<script>
標籤的src
屬性應該是你根目錄檔案的相對路徑————當然請確保你的web伺服器在執行。你的<script>
標籤應該看起來像是這樣:
<script src="pixi.min.js"></script>
這是你用來連結Pixi和測試它是否工作的基礎頁面。(這裡假設 pixi.min.js
在一個叫做pixi
的子資料夾中):
<!doctype html> <html> <head> <meta charset="utf-8"> <title>Hello World</title> </head> <script src="pixi/pixi.min.js"></script> <body> <script type="text/javascript"> let type = "WebGL" if(!PIXI.utils.isWebGLSupported()){ type = "canvas" } PIXI.utils.sayHello(type) </script> </body> </html>
如果Pixi連線成功,一些這樣的東西會在你的瀏覽器控制檯裡顯示:
PixiJS 4.4.5 - * canvas * http://www.pixijs.com/ ♥♥♥
建立Pixi應用和 舞臺
現在你可以開始使用Pixi!
但是怎麼用?
第一步就是去建立一個可以顯示圖片的矩形顯示區。Pixi擁有一個Pixi應用
物件來幫助你建立它。它會自動建立一個<canvas>
HTML標籤並且計算出怎麼去讓你的圖片在這個標籤中顯示。你現在需要建立一個特殊的Pixi容器
物件,他被稱作舞臺
。正如你所見,這個舞臺
物件將會被當作根容器而使用,它將包裹所有你想用Pixi顯示的東西。
這裡是你需要建立一個名叫app
的Pixi應用物件和一個舞臺
的必要的程式碼。這些程式碼需要在你的HTML文件中以<script>
標籤包裹。
//Create a Pixi Application let app = new PIXI.Application({width: 256, height: 256}); //Add the canvas that Pixi automatically created for you to the HTML document document.body.appendChild(app.view);
這是你想要開始使用Pixi的最基本的程式碼。它在你的文件中建立了一個256畫素寬高的黑色canvas標籤。當你執行這個程式碼的時候瀏覽器應該顯示成這樣:
啊哈, 一個 black square!
PIXI.Application
算出了應該使用Canvas還是WebGL去渲染圖象,它取決於你正在使用的瀏覽器支援哪一個。它的引數是一個被稱作options
的物件。在這兒例子中,它的width
和 height
屬性已經被設定了,它們決定了canvas的寬和高(單位是畫素)。你能夠在options
物件中使用更多的屬性設定,這裡展示了你如何使用它來圓滑邊界,設定透明度和解析度:
let app = new PIXI.Application({ width: 256, // default: 800 height: 256, // default: 600 antialias: true, // default: false transparent: false, // default: false resolution: 1 // default: 1 } );
如果你覺得Pixi的預設設定也不錯,你就不需要作任何的設定,但是如果你需要,就在這裡看一下Pixi的文件吧:PIXI.Application.
這些設定做了些什麼呢? antialias
使得字型的邊界和幾何圖形更加圓滑(WebGL的anti-aliasing在所有平臺都不可用,所以你需要在你的遊戲的標籤平臺上測試他們)。transparent
將整個Canvas標籤的透明度進行了設定。resolution
讓Pixi在不同的解析度和畫素密度的平臺上執行變得簡單。設定解析度對於這個教程而言有些超綱了,到那時你可以看Mat Grove'sexplanation之中是如何使用resolution
的所有細節的。但是平常,只要保持resolution
是1,就可以應付大多數工程了。
Pixi的畫布
物件將會預設選擇WebGL引擎渲染模式,它更快並且可以讓你使用一些壯觀的視覺特效————如果你把他們都學了。但是如果你需要強制使用Canvas引擎繪製而拋棄WebGL,你可以設定forceCanvas
選項為true
,像這樣:
forceCanvas: true,
如果你需要在你建立canvas標籤之後改變它的背景色,設定 app.renderer
物件的backgroundColor
屬性為一個任何的十六進位制顏色:
app.renderer.backgroundColor = 0x061639;
如果你想要去找到畫布
的寬高,使用app.renderer.view.width
和app.renderer.view.height
。
使用畫布
的resize
方法可以改變canvas的大小,提供任何新的width
和 height
變數給他都行。但是為了確認寬高的格式正確,將autoResize
設定為true
。
app.renderer.autoResize = true; app.renderer.resize(512, 512);
如果你想讓canvas佔據整個視窗,你可以將這些CSS程式碼放在文件中,並且重新整理你瀏覽器視窗的大小。
app.renderer.view.style.position = "absolute";
app.renderer.view.style.display = "block";
app.renderer.autoResize = true;
app.renderer.resize(window.innerWidth, window.innerHeight);
但是,如果你這麼做了,要記得把padding和margin都設定成0:
<style>* {padding: 0; margin: 0}</style>
(*這個萬用字元, 是CSS選擇所有HTML元素的意思。)
如果你想要canvas在任何瀏覽器中統一尺寸,你可以使用scaleToWindow
成員函式.
Pixi 精靈
現在你就有了一個畫布,可以開始往上面放影象了。所有你想在畫布上顯示的東西必須被加進一個被稱作 舞臺
的Pixi物件中。你能夠像這樣使用舞臺物件:
app.stage
這個舞臺
是一個Pixi 容器
物件。你能把它理解成一種將放進去的東西分組並存儲的空箱子。 舞臺
物件是在你的場景中所有可見物件的根容器。所有你放進去的東西都會被渲染到canvas中。現在舞臺
是空的,但是很快我們就會放進去一點東西。 (你可以從這瞭解關於Pixi容器
物件的更多資訊here).
(重要資訊:因為舞臺
是一個Pixi容器
物件,所以他有很多其他容器
物件都有的屬性和方法。但是,儘管舞臺擁有width
和 height
屬性, 他們都不能檢視畫布視窗的大小 。舞臺的width
和 height
屬性僅僅告訴了你你放進去的東西佔用的大小 - 更多的資訊在前面!)
所以你可以放些什麼到舞臺上呢?那就是被稱作 精靈 的特殊影象物件。精靈是你能用程式碼控制影象的基礎。你能夠控制他們的位置,大小,和許多其他有用的屬性來產生互動和動畫。學習怎樣建立和控制精靈是學習Pixi最重要的部分。如果你知道怎麼建立精靈和把他們新增進舞臺,離做出一個遊戲就僅僅剩下一步之遙!
Pixi擁有一個精靈
類來建立遊戲精靈。有三種主要的方法來建立它:
- 用一個單影象檔案建立。
- 用一個 雪碧圖 來建立。雪碧圖是一個放入了你遊戲所需的所有影象的大圖。
- 從一個紋理貼圖集中建立。(紋理貼圖集就是用JSON定義了影象大小和位置的雪碧圖)
你將要學習這三種方式,但是在開始之前,你得弄明白圖片怎麼用Pixi顯示。
將圖片載入到紋理快取中
因為Pixi用WebGL和GPU去渲染影象,所以影象需要轉化成GPU可以處理的版本。可以被GPU處理的影象被稱作 紋理 。在你讓精靈顯示圖片之前,需要將普通的圖片轉化成WebGL紋理。為了讓所有工作執行的快速有效率,Pixi使用 紋理快取 來儲存和引用所有你的精靈需要的紋理。紋理的名稱字串就是影象的地址。這意味著如果你有從"images/cat.png"
載入的影象,你可以在紋理快取中這樣找到他:
PIXI.utils.TextureCache["images/cat.png"];
紋理被以WEBGL相容的格式儲存起來,它可以使Pixi的渲染有效率的進行。你現在可以使用Pixi的精靈
類來建立一個新的精靈,讓它使用紋理。
let texture = PIXI.utils.TextureCache["images/anySpriteImage.png"]; let sprite = new PIXI.Sprite(texture);
但是你該怎麼載入影象並將它轉化成紋理?答案是用Pixi已經構建好的loader
物件。
Pixi強大的loader
物件可以載入任何你需要種類的影象資源。這裡展示了怎麼載入一個影象並在載入完成時用一個叫做setup
的方法來使用它。
PIXI.loader .add("images/anyImage.png") .load(setup); function setup() { //This code will run when the loader has finished loading the image }
Pixi的最佳實踐 如果你使用了Loader,你就應該建立一個精靈來連線loader
的resources
物件,像下面這樣:
let sprite = new PIXI.Sprite( PIXI.loader.resources["images/anyImage.png"].texture );
這裡是一個完整的載入影象的程式碼。呼叫setup
方法,並未載入的影象建立一個精靈。
PIXI.loader .add("images/anyImage.png") .load(setup); function setup() { let sprite = new PIXI.Sprite( PIXI.loader.resources["images/anyImage.png"].texture ); }
這是這個教程之中用來載入影象和建立精靈的通用方法。
你可以鏈式呼叫add
方法來載入一系列影象,像下面這樣:
PIXI.loader .add("images/imageOne.png") .add("images/imageTwo.png") .add("images/imageThree.png") .load(setup);
更好的方式則是用陣列給一個add
方法傳參,像這樣:
PIXI.loader .add([ "images/imageOne.png", "images/imageTwo.png", "images/imageThree.png" ]) .load(setup);
這個loader
也允許你使用JSON檔案,關於JSON檔案你應該已經在前面學過了。
顯示精靈
在你載入一個影象之後,可以用它來建立一個精靈,你需要用stage.addChild
方法把它放到Pixi的舞臺
上面去,像這樣:
app.stage.addChild(cat);
記住,舞臺
是用來包裹你所有精靈的主要容器。
重點:你不應該看見任何沒被加入舞臺
的精靈
在我們繼續之前,讓我們看一個怎樣使用顯示一個單影象的例子。在examples/images
資料夾中,你將找到一個64*64畫素大小的貓的PNG影象檔案。
這裡是所有的顯示一個影象,建立一個精靈,顯示在Pixi的舞臺上所需要的程式碼。
//Create a Pixi Application let app = new PIXI.Application({ width: 256, height: 256, antialias: true, transparent: false, resolution: 1 } ); //Add the canvas that Pixi automatically created for you to the HTML document document.body.appendChild(app.view); //load an image and run the `setup` function when it's done PIXI.loader .add("images/cat.png") .load(setup); //This `setup` function will run when the image has loaded function setup() { //Create the cat sprite let cat = new PIXI.Sprite(PIXI.loader.resources["images/cat.png"].texture); //Add the cat to the stage app.stage.addChild(cat); }
程式跑起來,你會看到:
現在我們已經取得了一些進展!
如果你想把一個精靈從舞臺上挪走,就可以使用removeChild
方法:
app.stage.removeChild(anySprite)
但是通常,我們都把精靈的visible
屬性設定成false
來讓精靈簡單的隱藏。
anySprite.visible = false;
使用別名
你可以對你使用頻繁的Pixi物件和方法設定一些簡略的可讀性更強的別名。舉個例子,你想給所有的Pixi物件增加PIXI
字首麼?如果你這樣想,那就建立一個簡短的別名給他吧。下面是一個給TextureCache
物件建立別名的例子:
let TextureCache = PIXI.utils.TextureCache
現在就可以像這樣使用別名了:
let texture = TextureCache["images/cat.png"];
使用別名給寫出簡潔的程式碼提供了額外的好處:他幫助你快取了Pixi的常用API。如果Pixi的API在將來的版本里改變了 - 沒準他真的會變! - 你將會需要在一個地方更新這些物件和方法,你只用在工程的開頭而不是所有的例項那裡!所以Pixi的開發團隊想要改變它的時候,你只用一步即可完成這個操作!
來看看怎麼將所有的Pixi物件和方法改成別名之後,來重寫載入和顯示影象的程式碼。
//Aliases let Application = PIXI.Application, loader = PIXI.loader, resources = PIXI.loader.resources, Sprite = PIXI.Sprite; //Create a Pixi Application let app = new Application({ width: 256, height: 256, antialias: true, transparent: false, resolution: 1 } ); //Add the canvas that Pixi automatically created for you to the HTML document document.body.appendChild(app.view); //load an image and run the `setup` function when it's done loader .add("images/cat.png") .load(setup); //This `setup` function will run when the image has loaded function setup() { //Create the cat sprite let cat = new Sprite(resources["images/cat.png"].texture); //Add the cat to the stage app.stage.addChild(cat); }
大多數教程中的例子將會使用Pixi的別名來處理。除非另有說明,否則你可以假定下面所有的程式碼都使用了這些別名。
這就是你需要的所有的關於載入影象和建立精靈的知識。
一些關於載入的其他知識
我們的例子中的格式是載入影象和顯示精靈的最佳實踐。所以你可以安全的忽視這些章節直接看"定位精靈"。但是Pixi的載入器有一些你不常用的複雜功能。
使用普通的javaScript Img物件或canvas建立一個精靈
為了優化和效率我們常常選擇從預載入的紋理快取的紋理之中建立精靈。但是如果因為某些原因你需要從JavaScript的Image
物件之中建立,你可以使用Pixi的BaseTexture
和Texture
類:
let base = new PIXI.BaseTexture(anyImageObject), texture = new PIXI.Texture(base), sprite = new PIXI.Sprite(texture);
你可以使用BaseTexture.fromCanvas
從任何已經存在canvas標籤中建立紋理:
let base = new PIXI.BaseTexture.fromCanvas(anyCanvasElement),
如果你想改變已經顯示的精靈的紋理,使用texture
屬性,可以設定任何Texture
物件,像下面這樣:
anySprite.texture = PIXI.utils.TextureCache["anyTexture.png"];
你可以使用這個技巧在遊戲發生一些重大變化時互動式的改變精靈的紋理。
給載入的檔案設定別名
你可以給任何你載入的原始檔分配一個獨一無二的別名。你只需要在add
方法中第一個引數位置傳進去這個別名就行了,舉例來說,下面實現了怎麼給這個貓的圖片重新命名為catImage
。
PIXI.loader .add("catImage", "images/cat.png") .load(setup);
這種操作在loader.resources
中建立了一個叫做catImage
的物件。 這意味著你可以建立一個引用了catImage
物件的精靈,像這樣:
let cat = new PIXI.Sprite(PIXI.loader.resources.catImage.texture);
然而,我建議你永遠別用這個操作!因為你將不得不記住你所有載入檔案的別名,而且必須確信你只用了它們一次,使用路徑命名,我們將將這些事情處理的更簡單和更少錯誤。
監視載入程序
Pixi的載入器有一個特殊的progress
事件,它將會呼叫一個可以定製的函式,這個函式將在每次檔案載入時呼叫。progress
事件將會被loader
的on
方法呼叫,像是這樣:
PIXI.loader.on("progress", loadProgressHandler);
這裡展示了怎麼將on
方法注入載入鏈中,並且每當檔案載入時呼叫一個使用者定義的名叫loadProgressHandler
的函式。
PIXI.loader .add([ "images/one.png", "images/two.png", "images/three.png" ]) .on("progress", loadProgressHandler) .load(setup); function loadProgressHandler() { console.log("loading"); } function setup() { console.log("setup"); }
每一個檔案載入,progress事件呼叫loadProgressHandler
函式在控制檯輸出 "loading"。當三個檔案都載入完畢,setup
方法將會執行,下面是控制檯的輸出:
loading loading loading setup
這就不錯了,不過還能變的更好。你可以知道哪個檔案被載入了以及有百分之多少的檔案被載入了。你可以在loadProgressHandler
增加loader
引數和resource
引數實現這個功能,像下面這樣:
function loadProgressHandler(loader, resource) { /*...*/ }
你現在可以使用 resource.url
變數來找到現在已經被載入的檔案。(如果你想找到你定義的別名,使用resource.name引數。)你可以使用loader.progress
來找到現在有百分之多少的檔案被載入了,這裡有一些關於上面描述的程式碼:
PIXI.loader .add([ "images/one.png", "images/two.png", "images/three.png" ]) .on("progress", loadProgressHandler) .load(setup); function loadProgressHandler(loader, resource) { //Display the file `url` currently being loaded console.log("loading: " + resource.url); //Display the percentage of files currently loaded console.log("progress: " + loader.progress + "%"); //If you gave your files names as the first argument //of the `add` method, you can access them like this //console.log("loading: " + resource.name); } function setup() { console.log("All files loaded"); }
這裡是程式執行後的控制檯顯示:
loading: images/one.png progress: 33.333333333333336% loading: images/two.png progress: 66.66666666666667% loading: images/three.png progress: 100% All files loaded
這實在太酷了!因為你能用這個玩意做個進度條出來。 (注意:還有一些額外的resource
物件屬性, resource.error
會告訴你有哪些載入時候的錯誤,resource.data
將會給你檔案的原始二進位制資料。)
一些關於Pixi的載入器的其他知識
Pixi的載入器有很多可以設定的功能,讓我速覽一下:
add
方法有四個基礎引數:
add(name, url, optionObject, callbackFunction)
這裡有文件裡面對這些引數的描述:
name
(string): 載入原始檔的別名,如果沒設定,url
就會被放在這.url
(string): 原始檔的地址,是載入器 baseUrl
的相對地址.options
(object literal): 載入設定.options.crossOrigin
(Boolean): 原始檔請求跨域不?預設是自動設定的。options.loadType
: 原始檔是怎麼載入進來的?預設是Resource.LOAD_TYPE.XHR
。 options.xhrType
: 用XHR的時候該怎麼處理資料? 預設是Resource.XHR_RESPONSE_TYPE.DEFAULT
。callbackFunction
: 當這個特定的函式載入完,這個特定的函式將會被執行。
只有url
必填(你總得載入個檔案吧。)
這裡有點用了add
方法載入檔案的例子。第一個就是文件裡所謂的“正常語法”:
.add('key', 'http://...', function () {}) .add('http://...', function () {}) .add('http://...')
這些就是所謂“物件語法”啦:
.add({ name: 'key2', url: 'http://...' }, function () {}) .add({ url: 'http://...' }, function () {}) .add({ name: 'key3', url: 'http://...' onComplete: function () {} }) .add({ url: 'https://...', onComplete: function () {}, crossOrigin: true })
你也可以給add
方法傳一個物件的陣列,或者既使用物件陣列,又使用鏈式載入:
.add([ {name: 'key4', url: 'http://...', onComplete: function () {} }, {url: 'http://...', onComplete: function () {} }, 'http://...' ]);
(注意:如果你需要重新載入一批檔案,呼叫載入器的reset
方法:PIXI.loader.reset();
)
Pixi的載入器還有許多其他的高階特性,包括可以讓你載入和解析所有型別二進位制檔案的選項。這些並非你每天都要做的,也超出了這個教程的範圍,所以從GitHub專案中獲取更多資訊吧!
精靈位置
現在你知道了怎麼建立和顯示一個精靈,讓我們學習如何定位他們的位置和改變他們的大小 在最早的示例裡那個貓的精靈被放在了舞臺的左上角。它的x
和y
座標都是0。你可以通過改變它的x
和y
座標的值來改變他們的位置。下面的例子就是你通過設定x
和y
為96座標讓它在舞臺上居中。
cat.x = 96; cat.y = 96;
在你建立這個精靈之後,把這兩行程式碼放進setup
方法。
function setup() { //Create the `cat` sprite let cat = new Sprite(resources["images/cat.png"].texture); //Change the sprite's position cat.x = 96; cat.y = 96; //Add the cat to the stage so you can see it app.stage.addChild(cat); }
(注意:在這個例子裡,Sprite
是 PIXI.Sprite
的別名,TextureCache
是PIXI.utils.TextureCache
的別名,resources
是PIXI.loader.resources
的別名,我從現在開始在程式碼中使用這些別名。)
這兩行程式碼將把貓往右移動96畫素,往下移動96畫素。
這隻貓的左上角(它的左耳朵)(譯者注:從貓的角度看其實是它的右耳朵。。。)表示了它的x
和 y
座標點。為了讓他向右移動,增加x
這個屬性的值,為了讓他向下移動,就增加y
屬性的值。如果這隻貓的x
屬性為0,他就呆在舞臺的最左邊,如果他的y
屬性為0,他就呆在舞臺的最上邊。
你可以一句話設定精靈的x
和y
:
sprite.position.set(x, y)
大小和比例
你能夠通過精靈的width
和height
屬性來改變它的大小。這是怎麼把width
調整成80畫素,height
調整成120畫素的例子:
cat.width = 80; cat.height = 120;
在setup
函式裡面加上這兩行程式碼,像這樣:
function setup() { //Create the `cat` sprite let cat = new Sprite(resources["images/cat.png"].texture); //Change the sprite's position cat.x = 96; cat.y = 96; //Change the sprite's size cat.width = 80; cat.height = 120; //Add the cat to the stage so you can see it app.stage.addChild(cat); }
結果看起來是這樣:
你能看見,這隻貓的位置(左上角的位置)沒有改變,只有寬度和高度改變了。
精靈都有scale.x
和 scale.y
屬性,他們可以成比例的改變精靈的寬高。這裡的例子把貓的大小變成了一半:
cat.scale.x = 0.5; cat.scale.y = 0.5;
Scale的值是從0到1之間的數字的時候,代表了它對於原來精靈大小的百分比。1意味著100%(原來的大小),所以0.5意味著50%(一半大小)。你可以把這個值改為2,這就意味著讓精靈的大小成倍增長。像這樣:
cat.scale.x = 2; cat.scale.y = 2;
Pixi可以用一行程式碼縮放你的精靈,那要用到scale.set
方法。
cat.scale.set(0.5, 0.5);
如果你喜歡這種,就用吧!
旋轉
你可以通過對一個精靈的rotation
設定一個角度來旋轉它。
cat.rotation = 0.5;
但是旋轉是針對於哪一個點發生的呢? 你已經瞭解了,精靈的左上角代表它的位置,這個點被稱之為 錨點 。如果你用像0.5
這種值設定rotation
,這個旋轉將會 圍繞著錨點發生 。下面這張圖就是結果:
你能看見錨點是貓的左邊耳朵(譯者:對貓來說實際上是它的右耳朵!),那裡成了貓的圖片的旋轉中心。 你該怎麼改變錨點呢?通過改變精靈的anchor
屬性的xy值來實現。像下面這樣:
cat.anchor.x = 0.5; cat.anchor.y = 0.5;
anchor.x
和anchor.y
的值如果是從0到1,就會被認為是整個紋理的長度或寬度百分比。設定他們都為0.5,錨點就處在了影象中心。精靈定位的依據點不會改變,錨點的改變是另外一回事。
下面的圖顯示把錨點居中以後旋轉的精靈。
你可以看到精靈的紋理向左移動了,這是個必須記住的重要副作用!
像是position
和scale
屬性一樣,你也可以在一行內像這樣設定錨點的位置:
cat.anchor.set(x, y)
精靈也提供和anchor
差不多的pivot
屬性來設定精靈的原點。如果你改變了它的值之後旋轉精靈,它將會圍繞著你設定的原點來旋轉。舉個例子,下面的程式碼將精靈的pivot.x
和pivot.y
設定為了32。
cat.pivot.set(32, 32)
假設精靈圖是64x64畫素,它將繞著它的中心點旋轉。但是記住:你如果改變了精靈的pivot
屬性,你也就改變了它的原點位置。
所以anchor
和 pivot
的不同之處在哪裡呢?他們真的很像!anchor
改變了精靈紋理的影象原點,用0到1的資料來填充。pivot
則改變了精靈的原點,用畫素的值來填充。你要用哪個取決於你。兩個都試試就知道哪個對你而言最適合。
從精靈圖(雪碧圖)中建立精靈【為了防止與精靈混淆,我在之後的譯文中都將採用雪碧圖這一譯法】
你現在已經知道了怎麼從一個單檔案內載入影象。但是作為一個遊戲設計師,你沒準更經常使用 雪碧圖(也被稱之為 精靈圖)。Pixi封裝了一些方便的方式來處理這種情況。所謂雪碧圖就是用一個單檔案包含你遊戲中需要的所有檔案,這裡就是一個包含了遊戲物件和遊戲角色的雪碧圖。
整個雪碧圖是192192畫素寬高,但每一個單影象只佔有一個3232的網格。把你的所有遊戲影象儲存在一個雪碧圖上是一個非常有效率和工程化的手段,Pixi為此做出了優化。你可以從一個雪碧圖中用一個矩形區域捕獲一個子影象。這個矩形擁有和你想提取的子影象一樣的大小和位置。這裡有一個怎麼從一個精靈圖中獲取“火箭”這個子影象的例子。
讓我們看看這部分的程式碼,用Pixi的載入器
載入tileset.png
,就像你在之前的示例之中做到的那樣。
loader .add("images/tileset.png") .load(setup);
現在,在影象被載入之後,用一個矩形塊去擷取雪碧圖來建立精靈的紋理。下面是提取火箭,建立精靈,在canvas上顯示它的程式碼。
function setup() { //Create the `tileset` sprite from the texture let texture = TextureCache["images/tileset.png"]; //Create a rectangle object that defines the position and //size of the sub-image you want to extract from the texture //(`Rectangle` is an alias for `PIXI.Rectangle`) let rectangle = new Rectangle(192, 128, 64, 64); //Tell the texture to use that rectangular section texture.frame = rectangle; //Create the sprite from the texture let rocket = new Sprite(texture); //Position the rocket sprite on the canvas rocket.x = 32; rocket.y = 32; //Add the rocket to the stage app.stage.addChild(rocket); //Render the stage renderer.render(stage); }
它是如何工作的呢?
Pixi內建了一個通用的Rectangle
物件 (PIXI.Rectangle
),他是一個用於定義矩形形狀的通用物件。他需要一些引數,前兩個引數定義了x
和y
軸座標位置,後兩個引數定義了矩形的width
和 height
,下面是新建一個Rectangle
物件的格式。
let rectangle = new PIXI.Rectangle(x, y, width, height);
這個矩形物件僅僅是一個 資料物件,如何使用它完全取決於你。在我們的例子裡,我們用它來定義子影象在雪碧圖中的位置和大小。Pixi的紋理中有一個叫做frame
的很有用的屬性,它可以被設定成任何的Rectangle
物件。frame
將紋理對映到Rectangle
的維度。下面是怎麼用frame
來定義火箭的大小和位置。
let rectangle = new Rectangle(192, 128, 64, 64); texture.frame = rectangle;
你現在可以用它裁切紋理來建立精靈了:
let rocket = new Sprite(texture);
現在成功了! 因為從一個雪碧圖建立精靈的紋理是一個用的很頻繁的操作,Pixi有一個更加合適的方式來幫助你處理這件事情。欲知後事如何,且聽下回分解。
使用一個紋理貼圖集
如果你正在處理一個很大的,很複雜的遊戲,你想要找到一種快速有效的方式來從雪碧圖建立精靈。紋理貼圖集 就會顯得很有用處,一個紋理貼圖集就是一個JSON資料檔案,它包含了匹配的PNG雪碧圖的子影象的大小和位置。如果你使用了紋理貼圖集,那麼想要顯示一個子影象只需要知道它的名字就行了。你可以任意的排序你的排版,JSON檔案會保持他們的大小和位置不變。這非常方便,因為這意味著圖片的位置和大小不必寫在你的程式碼裡。如果你想要改變紋理貼圖集的排版,類似增加圖片,修改圖片大小和刪除圖片這些操作,只需要修改那個JSON資料檔案就行了,你的遊戲會自動給程式內的所有資料應用新的紋理貼圖集。你沒必要在所有用到它程式碼的地方修改它。
Pixi相容著名軟體Texture Packer輸出的標準紋理貼圖集格式。Texture Packer的基本功能是免費的。讓我們來學習怎麼用它來製作一個紋理貼圖集,並把它載入進Pixi吧!(你也不是非得用它,還有一些類似的工具輸出的紋理貼圖集Pixi也是相容的,例如:Shoebox和spritesheet.js。)
首先,從你要用在遊戲的圖片檔案們開始。
在這個章節所有的圖片都是被Lanea Zimmerman創作的。你能在他的藝術工作室裡面找到更多類似的東西:這裡,謝謝你,Lanea!
下面,開啟Texture Packer,選擇 JSON Hash 框架型別。把你的圖片放進Texture Packer的工作區。(你也可以把Texture Packer放進包含你圖片的資料夾裡面去。)他將自動的把你的圖片們生成單個圖片檔案,並且將他們的原始名稱命名為紋理貼圖集中的圖片名稱。
如果你正在用免費版的Texture Packer,把 Algorithm 選項設為Basic
,把 Trim mode 選項設為None
,把 Extrude 選項設為0
,把 Size constraints 選項設為 Any size
,把 PNG Opt Level 中所有的東西都滑到左邊的 0
位置。這就可以使得Texture Packer正常的輸出你的紋理貼圖集。
如果你做完了,點選 Publish 按鈕。選擇輸出檔名和儲存地址,把生成檔案儲存起來。你將會獲得兩個檔案:一個叫做treasureHunter.json
,另外一個就是treasureHunter.png
。為了讓目錄乾淨些,我們把他倆都放到一個叫做images
的資料夾裡面去。(你可以認為那個json檔案是圖片檔案的延伸,所以把他們放進一個資料夾是很有意義的。)那個JSON檔案裡面寫清楚了每一個子影象的名字,大小和位置。下面描述了“泡泡怪”這個怪物的子影象的資訊。
"blob.png": { "frame": {"x":55,"y":2,"w":32,"h":24}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":32,"h":24}, "sourceSize": {"w":32,"h":24}, "pivot": {"x":0.5,"y":0.5} },
treasureHunter.json
裡面也包含了“dungeon.png”, “door.png”, "exit.png", 和 "explorer.png"的資料資訊,並以和上面類似的資訊記錄。這些子影象每一個都被叫做 幀 ,有了這些資料你就不用去記每一個圖片的大小和位置了,你唯一要做的就只是確定精靈的 幀ID 即可。幀ID就是那些圖片的原始名稱,類似"blob.png"或者 "explorer.png"這樣。
使用紋理貼圖集的巨大優勢之一就是你可以很輕易的給每一個影象增加兩個畫素的內邊距。Texture Packer預設這麼做。這對於保護影象的 出血(譯者:出血是排版和圖片處理方面的專有名詞,指在主要內容周圍留空以便印刷或裁切)來說很重要。出血對於防止兩個圖片相鄰而相互影響來說很重要。這種情況往往發生於你的GPU渲染某些圖片的時候。把邊上的一兩個畫素加上去還是不要?這對於每一個GPU來說都有不同的做法。所以對每一個影象空出一兩個畫素對於顯示來說是最好的相容。
(注意:如果你真的在每個影象的周圍留了兩個畫素的出血,你必須時時刻刻注意Pixi顯示時候“丟了一個畫素”的情況。嘗試著去改變紋理的規模模式來重新計算它。texture.baseTexture.scaleMode = PIXI.SCALE_MODES.NEAREST;
,這往往發生於你的GPU浮點運算湊整失敗的時候。)
現在你明白了怎麼建立一個紋理貼圖集,來學習怎麼把他載入進你的遊戲之中吧。
載入紋理貼圖集
可以使用Pixi的loader
來載入紋理貼圖集。如果是用Texture Packer生成的JSON,loader
會自動讀取資料,並對每一個幀建立紋理。下面就是怎麼用loader
來載入treasureHunter.json
。當它成功載入,setup
方法將會執行。
loader .add("images/treasureHunter.json") .load(setup);
現在每一個影象的幀都被載入進Pixi的紋理快取之中了。你可以使用Texture Packer中定義的他們的名字來取用每一個紋理。
從已經載入的紋理貼圖集中建立精靈
通常Pixi給你三種方式從已經載入的紋理貼圖集中建立精靈:
- 使用
TextureCache
:
let texture = TextureCache["frameId.png"], sprite = new Sprite(texture);
- 如果你是使用的
loader
來載入紋理貼圖集, 使用loader的resources
:
let sprite = new Sprite( resources["images/treasureHunter.json"].textures["frameId.png"] );
- 要建立一個精靈需要輸入太多東西了! 所以我建議你給紋理貼圖集的
textures
物件建立一個叫做id
的別名,象是這樣:
let id = PIXI.loader.resources["images/treasureHunter.json"].textures;
現在你就可以像這樣例項化一個精靈了:
let sprite = new Sprite(id["frameId.png"]);
真不錯啊~!
這裡在setup
函式中用三種不同的建立方法建立和顯示了dungeon
, explorer
, 和 treasure
精靈。
//Define variables that might be used in more //than one function let dungeon, explorer, treasure, id; function setup() { //There are 3 ways to make sprites from textures atlas frames //1. Access the `TextureCache` directly let dungeonTexture = TextureCache["dungeon.png"]; dungeon = new Sprite(dungeonTexture); app.stage.addChild(dungeon); //2. Access the texture using throuhg the loader's `resources`: explorer = new Sprite( resources["images/treasureHunter.json"].textures["explorer.png"] ); explorer.x = 68; //Center the explorer vertically explorer.y = app.stage.height / 2 - explorer.height / 2; app.stage.addChild(explorer); //3. Create an optional alias called `id` for all the texture atlas //frame id textures. id = PIXI.loader.resources["images/treasureHunter.json"].textures; //Make the treasure box using the alias treasure = new Sprite(id["treasure.png"]); app.stage.addChild(treasure); //Position the treasure next to the right edge of the canvas treasure.x = app.stage.width - treasure.width - 48; treasure.y = app.stage.height / 2 - treasure.height / 2; app.stage.addChild(treasure); }
這裡是程式碼執行的結果:
舞臺定義為512畫素見方的大小,你可以看到程式碼中app.stage.height
和app.stage.width
屬性使得精靈們排成了一排。下面的程式碼使得explorer
的y
屬性垂直居中了。
explorer.y = app.stage.height / 2 - explorer.height / 2;
學會使用紋理貼圖集來建立一個精靈是一個基本的操作。所以在我們繼續之前,你來試著寫一些這樣的精靈吧:blob
們和exit
的門,讓他們看起來象是這樣:
下面就是所有的程式碼啦。我也把HTML放了進來,現在你可以看見所有的上下文。(你可以在examples/spriteFromTextureAtlas.html
找到可以用於演示的程式碼。)注意,blob
精靈是用一個迴圈加進舞臺的,並且他有一個隨機的位置。
<!doctype html> <meta charset="utf-8"> <title>Make a sprite from a texture atlas</title> <body> <script src="../pixi/pixi.min.js"></script> <script> //Aliases let Application = PIXI.Application, Container = PIXI.Container, loader = PIXI.loader, resources = PIXI.loader.resources, TextureCache = PIXI.utils.TextureCache, Sprite = PIXI.Sprite, Rectangle = PIXI.Rectangle; //Create a Pixi Application let app = new Application({ width: 512, height: 512, antialias: true, transparent: false, resolution: 1 } ); //Add the canvas that Pixi automatically created for you to the HTML document document.body.appendChild(app.view); //load a JSON file and run the `setup` function when it's done loader .add("images/treasureHunter.json") .load(setup); //Define variables that might be used in more //than one function let dungeon, explorer, treasure, door, id; function setup() { //There are 3 ways to make sprites from textures atlas frames //1. Access the `TextureCache` directly let dungeonTexture = TextureCache["dungeon.png"]; dungeon = new Sprite(dungeonTexture); app.stage.addChild(dungeon); //2. Access the texture using throuhg the loader's `resources`: explorer = new Sprite( resources["images/treasureHunter.json"].textures["explorer.png"] ); explorer.x = 68; //Center the explorer vertically explorer.y = app.stage.height / 2 - explorer.height / 2; app.stage.addChild(explorer); //3. Create an optional alias called `id` for all the texture atlas //frame id textures. id = PIXI.loader.resources["images/treasureHunter.json"].textures; //Make the treasure box using the alias treasure = new Sprite(id["treasure.png"]); app.stage.addChild(treasure); //Position the treasure next to the right edge of the canvas treasure.x = app.stage.width - treasure.width - 48; treasure.y = app.stage.height / 2 - treasure.height / 2; app.stage.addChild(treasure); //Make the exit door door = new Sprite(id["door.png"]); door.position.set(32, 0); app.stage.addChild(door); //Make the blobs let numberOfBlobs = 6, spacing = 48, xOffset = 150; //Make as many blobs as there are `numberOfBlobs` for (let i = 0; i < numberOfBlobs; i++) { //Make a blob let blob = new Sprite(id["blob.png"]); //Space each blob horizontally according to the `spacing` value. //`xOffset` determines the point from the left of the screen //at which the first blob should be added. let x = spacing * i + xOffset; //Give the blob a random y position //(`randomInt` is a custom function - see below) let y = randomInt(0, app.stage.height - blob.height); //Set the blob's position blob.x = x; blob.y = y; //Add the blob sprite to the stage app.stage.addChild(blob); } } //The `randomInt` helper function function randomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } </script> </body>
你可以看見所有的泡泡怪都用一個for
迴圈被建立了,每一個泡泡怪都有一個獨一無二的x
座標,像是下面這樣:
let x = spacing * i + xOffset; blob.x = x;
spacing
變數的值是48,xOffset
的值是150。這意味著第一個blob
怪的位置的x
座標將會是150。這個偏移使得泡泡怪離舞臺左邊的距離有150個畫素。每一個泡泡怪都有個48畫素的空餘,也就是說每一個泡泡怪都會比在迴圈之中前一個建立的泡泡怪的位置的x
座標多出48畫素以上的增量。它使得泡泡怪們相互間隔,從地牢地板的左邊排向右邊。 每一個blob
也被賦予了一個隨機的y
座標,這裡是處理這件事的程式碼:
let y = randomInt(0, stage.height - blob.height); blob.y = y;
泡泡怪的y
座標將會從0到512之間隨機取值,它的變數名是stage.height
。它的值是利用randomInt
函式來得到的。randomInt
返回一個由你定義範圍的隨機數。
randomInt(lowestNumber, highestNumber)
這意味著如果你想要一個1到10之間的隨機數,你可以這樣得到它:
let randomNumber = randomInt(1, 10);
這是randomInt
方法的定義:
function randomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }
randomInt
是一個很好的用來做遊戲的工具函式,我經常用他。
移動精靈
現在你知道了如何展示精靈,但是讓它們移動呢?很簡單:使用Pixi的ticker
。這被稱為 遊戲迴圈 。任何在遊戲迴圈裡的程式碼都會1秒更新60次。你可以用下面的程式碼讓 cat
精靈以每幀1畫素的速率移動。
function setup() { //Start the game loop by adding the `gameLoop` function to //Pixi's `ticker` and providing it with a `delta` argument. app.ticker.add(delta => gameLoop(delta)); } function gameLoop(delta){ //Move the cat 1 pixel cat.x += 1; }
如果你運行了上面的程