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