2012年6月14日 星期四

Unity3D教學 - 使用免費工具來開發2D遊戲(教學四)


本文轉載自 www.rocket5studios.com,版權歸原作者所有,UnityBuster.blogspot.com整理翻譯。轉載請註明出處!

本教學內容是要來教你如何使用一些免費的軟體工具在Unity3D中製作2D遊戲. 此一教材共分成五個部分, 連結與大綱分列於下:





使用免費工具來開發2D遊戲 - 教學一: 介紹本教學使用的工具和Unity3D的插件
使用免費工具來開發2D遊戲 - 教學二: 製作sprite(圖素原件)和第一個level(關卡)
使用免費工具來開發2D遊戲 - 教學三: 製作一個角色動畫sprite(圖素原件)並與控制腳本連結
使用免費工具來開發2D遊戲 - 教學四: 製作一個 "pickup" 物品以及計分介面並和與計分腳本連結
5: 使用 "A*尋徑" 的啟始敵人智能判斷

使用免費工具來開發2D遊戲 - 教學四

本教學將要製作一個 "pickup" 撿拾物品以及計分介面並和與計分腳本連結

增加 "計分" 和 "撿拾" 腳本
現在我們要開始製作一個寶箱(gold chest)和計分, 等級, 生命支數之顯示介面:

先在此下載計分和撿拾腳本: http://www.rocket5studios.com/files/Rocket5_2DGame_Scripts_pt4.zip

解壓縮後將 scoring.cs 及 pickup.cs 複製到你的專案中的 Assets/Scripts 目錄

修改現有之腳本:
我們要先修改現有之腳本好讓新的腳本可以起作用:

打開 xa.cs 腳本並將第一行註解拿掉:
public static Scoring sc;

在 Start 函數, 將此行註解拿掉:
sc = (Scoring)(this.gameObject.GetComponent("Scoring"));

打開 Player.cs 腳本並找到 OnTriggerEnter 函數, 將此段註解拿掉:

if (other.gameObject.CompareTag("Pickup"))
{
    if (other.GetComponent())
    {
        other.GetComponent().PickMeUp();
        xa.sc.Pickup();
    }
}

製作 "撿拾" 的圖素原件
還記得教學二中我們已經將 pickup.png 加入 level 原件圖集(sprite atlas) 中並製作了一個指向此原件圖集的level container (存放箱 )物件, 因此我們不再需要令作設定就可開始製作撿拾之圖素原件

到 "Orthello" 目錄: Orthello -> Objects -> Sprites 之後將 Sprite 物件拖曳放入 "Hierarchy" 或 "Scene" 命名為類似 "Sprite (id=-3700)" 的名稱. 將此物件更名為 "pickup"
將我們在教學二中製作的 level 物件從 OT -> Containers 拖曳放入"Inspector" 的 "Sprite Container" 槽中.

此 sprite 會顯現出之前作的磚頭圖素原件, 原因是磚頭是在原件圖集(sprite atlas) 中的第一個圖. 修正它:
選取撿拾物件後, 用鼠標按住 Inspector 中的 "Frame Index"並向右拖曳到原件圖集中的16號的圖案. 現在物件就呈現中央有紅色方塊的白色方形外觀了.

調整物理碰撞:
圖素原件是一個方形, 我們希望在角色碰到白色部份才會撿拾到該物品:
勾選 "Collidable" 將碰撞屬性賦予此物件
打開 Physics 旁的下拉選單並選取 Custom
在 Box Collider, 將 Center Y 設為 -0.15, Center X 設為 0.8, Size Y 設為 0.5,  Size Z 設為 0.4

設定標籤 Tag:
被撿拾物件需要加上標籤(tag), 如此當角色碰觸到此物件時才會被觸發:

到 Edit -> Project Settings -> Tags 來產生新的 tag
在 Tags 清單中加入一新的 Tag (目前應該在 Element 3) 並命名為 "Pickup". 此名和 Player.cs 中相對應, 別取錯名了.
在 Hierarchy中選取 pickup 物件, 並點選Inspector 上端 Tags 旁之下拉式清單後選擇 "Pickup"

加入腳本並讓其成為一個 Prefab
將 Pickup.cs 腳本賦加到圖素原件上, 如此當角色碰觸到該原件時會被檢起. 同時也要將其變成一個 prefab 以方便將其加入所有其他關卡

將 Pickup.cs 腳本從 Project Scripts 目錄拖曳到 Hierarchy 中的 pickup 原件上.
將Hierarchy 中的 pickup 物件拖曳到 Project 中之 Prefabs 目錄以產生 prefab

將此 prefab 複製幾個並散放在關卡中.



增加介面文字
到目前的階段, 你已經可以撿寶了, 可是會看到一些錯誤訊息, 這是因為計分腳本還未加入, 因而無法正確顯示得分:
先要加入 Scoring.cs 腳本: 將 Scoring.cs 從 Project的 Scripts 目錄拖曳到 Hierarchy 中的 Scripts 物件. 你如果選擇 Scripts 物件, 你會看到 Scoring 腳本有許多槽等著加入 text 物件, 因此, 我們要先產生這些 text 物件
從下面連結下載檔案:http://www.rocket5studios.com/files/G7_Silkworm.zip
解壓縮後存入硬碟中. 這是我們要使用的字型, 你也可以找自己喜歡的使用
在 Assets 目錄中產生一新的目錄並命名為 "Fonts", 從硬碟中找出 "silkworm.ttf" 字型並將其複製到 Assets/Fonts 目錄中
在Unity中, 從 Project的Fonts目錄選擇 silkworm 字型後在 Inspector 將 Font Size 設為 26.

產生計分之 text





製作頂端邊界






製作全域(GLOBAL)的 Prefab







製作角色的 Prefab










本文轉載自www.rocket5studios.com,版權歸原作者所有,UnityBuster.blogspot.com整理翻譯。轉載請註明出處!

2012年5月28日 星期一

Unity3D教學 - 使用免費工具來開發2D遊戲(教學三)


本文轉載自 www.rocket5studios.com,版權歸原作者所有,UnityBuster.blogspot.com整理翻譯。轉載請註明出處!

本教學內容是要來教你如何使用一些免費的軟體工具在Unity3D中製作2D遊戲. 此一教材共分成五個部分, 連結與大綱分列於下:





使用免費工具來開發2D遊戲 - 教學一: 介紹本教學使用的工具和Unity3D的插件
使用免費工具來開發2D遊戲 - 教學二: 製作sprite(圖素原件)和第一個level(關卡)
使用免費工具來開發2D遊戲 - 教學三: 製作一個角色動畫sprite(圖素原件)並與控制腳本連結
使用免費工具來開發2D遊戲 - 教學四: 製作一個 "pickup" 物品以及計分介面並和與計分腳本連結
5: 使用 "A*尋徑" 的啟始敵人智能判斷


使用免費工具來開發2D遊戲 - 教學三

有了關卡, 接下來就要有角色可以在遊戲裡跑來跑去了.

製作角色原件圖集 Sprite Atlas

由這個連結下載圖檔解開後放在硬碟中使用: (如果你在教學二已經加入專案就可省略)
http://www.rocket5studios.com/files/Rocket5_2DGame_LevelSprites.zip
啟動 "TexturePacker", 從 sprites/player 目錄把所有的 .png 檔拖曳到 Sprites panel 中.

Texture Settings / Layout:
將 Algorithm 設為 Basic
將 Border Padding 設為 1
將 Shape Padding 設為 1
取銷 Trim

Texture Settings / Output:
保留 Data 格式為 cocos2d
在 Data File, 點選 "..." 按鈕, 看看要把這些圖素原件存在本專案的 "Asset" 目錄的哪裡. (我是存在 Assets/SpriteAtlases), 將其取名為 "player" 後點選 "Save" 儲存
TexturePacker 會將Data File的副檔名自動設為 .plist, 但由於 Unity 希望是 .xml檔, 所以我們在文字欄中將 .plist 改為 .xml.
除非有 .png 副檔我們無能為力之外, 貼圖檔路徑應該已經設成和 .xml 同一路徑了

TexturePacker 現在看起來應該是這樣:

如果你現在在 TexturePacker中按下 "Publish" 並轉回 Unity3D, 你應會看到原件圖集(sprite atlas) 包括了 player.png 和 player.xml 圖素原件檔的 "SpriteAtlases" 目錄出現在 "Project" 中.
如果你現在還沒在Unity中打開你的專案,  打開它後把你在教學二製作的 level1.scene 載入

我們需要對原件圖集 Sprite Atlas 作些更改:
從 Project 中選取 player.png 後, 在 Inspector 將 Filter Mode 設為 Point
點選 Override for Web 方盒, 將 Format 設為 Truecolor 後按 Apply

製作角色圖素原件 Sprite
接下來是要用 Orthello 將 player 的 "原件圖集" 轉變成 "圖素原件"(sprite)

圖素原件存放箱 (Sprite Container)
在 "Project" view中, 到 "Orthello" 目錄: Orthello -> Objects -> Sprites -> SpriteAtlas 之後將 SpriteAtlas-Cocos2D 物件拖曳放入 "Hierarchy"
在 "Hierarchy" 中, 展開 "OT" 物件以及 "Containers" 物件, 你會發現你的新存放箱 (Container" 被命名為類似 "Container (id=-6840)" 的名稱. 我們由原件圖集(sprite atlas)製作出來的 "關卡圖素原件" 將會放入此存放箱中, 你可以將其改名為, 如 "player".
從 "Project, SpriteAtlases" 目錄中將 "player.png" 拖曳並放入 "OTSprite Atlas Cocos 2D" 腳本的 "Texture" 槽中.
從 "Project, SpriteAtlases" 目錄中將 "player.xml" 拖曳並放入 "Atlas Data File" 槽中. 如果你現在將 Atlas Data 的小箭頭往下拉, 會發現已被 TexturePacker 產生之原件圖集內的資料所充滿了.

製作角色動畫
從 Orthello -> Objects -> Sprites 中將 "Animation"物件拖曳放入 "Hierarchy". 如此會在 OT -> Animations 增加一個名為 "Animation (id=-4320)" 之類的新物件, 將其更名為 "player anims".
趁著OTAnimation還被選取, 依下圖更改其設定
將 "player" 物件從 OT -> Containers 中拖曳放入 Container field 以將其發佈到 Container field


製作角色圖素原件(sprite)
從 Orthello -> Objects -> Sprites 中將 "AnimatingSprite" 物件拖曳放入"Hierarchy". 如此會在 OT -> Animations 增加一個名為 "AnimatingSprite (id=-23050)" 之類的新物件, 將其更名為 "player".
趁著player物件還被選取,將 "player anims" 物件拖曳放入 "Animation" 槽, "Sprite Container" 槽會自動被一個參考到 "player" container 物件填滿.
你現在會看到場景中角色的sprite, 按 "Play", 動畫會開始播放. 由於我們並不要在開始就播動畫, 因此取銷 "Play On Start" 之勾選


製作角色碰撞 (抗力) Collision 屬性

趁著player物件還被選取, 勾選 "Collidable" 項,   將 "Box Collider" 和 "Rigidbody" 加入圖素原件中
點選 Physics 旁的下拉式選單並選擇 Custom
在 Transform, 將 Scale Z 設為 1
將 Depth 設為 -1
在 "Box Collider" , 設 Center Y 為 -0.1, 設 Z 為 1, 設 Size X 為 -0.45, 設 Y 為 0.6, 設 Z 為 0.4
設定如下圖:


當角色圖素面對鏡頭位移 1 單位時, 在 "Box Collider" 中將 Depth 設為 -1, 將 Center Z 設為 1 會將 抗力點置於 Z 軸 0 的位置. 如此會產生兩種效果: 將抗力碰撞一直保持設定在 Z 軸之 0 時確認角色一直都會顯現在關卡圖素之前且會保證和 梯子及繩索接觸. 參考下圖:



設定射擊動畫
角色按下射擊鈕時會出現一個子彈動畫從角色發出射往地上

射擊動畫
從 Orthello -> Objects -> Sprites 中將 "Animation"物件拖曳放入 "Hierarchy". 如此會在 OT -> Animations 增加一個名為 "Animation (id=-4320)" 之類的新物件, 將其更名為 "shoot anims".
趁著OTAnimation還被選取, 依下圖更改其設定. 將 "level" 物件從 OT -> Containers 中拖曳放入 Container field 以將其發佈到 Container field. 僅記我們之前已經在教學二中將 shoot sprite animation 加入 關卡圖集中了.


射擊圖素 (Shoot Sprite)
從 Orthello -> Objects -> Sprites 中將 "AnimatingSprite" 物件拖曳放入"Hierarchy". 如此會在 OT -> Animations 增加一個名為 "AnimatingSprite (id=-23050)" 之類的新物件, 將其更名為 "shoot".
趁著shoot物件還被選取,將 "shoot anims" 物件拖曳放入 "Animation" 槽, "Sprite Container" 槽會自動被一個參考到 "level" container 物件填滿
為了讓此圖素出現在關卡圖素前, 將 Depth 設為 -1
將 Frame Index 設為 18

現在應可看到一個 shoot 的圖素原件出現在畫面, 如果在Unity中按 "Play"即可看到動畫, 由於我們並不要在開始就播動畫, 因此取銷 "Play On Start" 之勾選

我們只希望在玩家射擊時才出現 shoot 圖素, 因此取銷shoot sprite上的 "Mesh Render" 之勾選. 如此 shoot sprite 就會被隱藏在場景後面直到被下面教學所寫的腳本叫出

為射擊圖素 (Shoot Sprite) 尋找主人
射擊圖素應是跟著射擊者而動, 且當角色左右轉變方向時, 射擊圖素也會跟著反轉過來:

選擇: Game Object -> Create Empty
將此新物件更名為 "shoot parent" 並確認此新物件 X, Y, Z Position 設為 0
在 Hierarchy, 將 "shoot sprite" 拖曳放在 "shoot parent" 上, 如此  "shoot sprite" 就會成為 "shoot parent" 的追隨者(child).
將 "shoot parent" 物件拖曳放在 "player sprite" 讓它成為 "player sprite" 的追隨者(child).

結果如下圖:


與腳本 Script 結合
現在開始加入可移動角色的腳本

先到此處下載腳本: http://www.rocket5studios.com/files/Rocket5_2DGame_Scripts_Pt3.zip 並解壓存入你的電腦
將解壓後的 "Scripts" 目錄拖曳到你 "Project" 中的 "Asset"目錄中
選擇 "Game Object -> Create Empty" 以建立一個新的遊戲物件並更名為 "Scripts"
從 "Project" 中將 xa.cs 檔案拖曳到 Hierarchy 中的 "Scripts" 物件
從 "Project" 中將 player.cs 和 playerAnims.cs 檔案拖曳到 Hierarchy 中的 "player" 物件
確認 "player" 物件置於磚塊上方如此才有地方站住. 要注意實際上是 "player" 的 "Box Collider" 在與此遊戲世界中的物體發生接觸與碰撞的. 因此方塊需要置於像是類似於 0,0,-1 之處 (x, y, z)中, x, y 可以是任一值, z 則要保持為 -1

現在如果在Unity中按 "Play"即可看 "Player" 是站立在一個磚塊上而不會穿過它而掉落. 當你按左/右鍵時動作會跟著變化.

加入梯子碰撞機 Collider
產生一個梯子:
選擇 GameObject -> Create Other -> Cube 並將 Cube 更名為 Ladder
到 Edit -> Project Setting -> Tags 以打開 "Tag manager"
在最近的可使用的空槽(可能是 Element 1) 中的 "Tags" 填入 "Ladder" 後, 並在緊接其後的空槽中填入 "Rope"
同時還要新增另一個 layer: 在下一個空的 "User Layer" (可能是 User Layer 9) 輸入 "NoDraw"
點選之前產生的 Ladder 方塊並將 Tag 改成 "Ladder" 後將 Layer 變更為 "NoDraw"

將物件隱藏在Game View 中:
碰撞機不需要出現在遊戲畫面中, 我們藉由調整 camera 來達到此目的:
在 Hierarchy 中點選 Main Camera
在 Camera 底下, 下拉 Culling Mask 旁的選單並點擊在 "NoDraw" 上來取銷它的出現.

設定 Ladder 之大小與位置:
場景中的每一個梯子都必需搭配一個這樣的碰撞機並且其 "Scale Y" 值要為 5 (比畫面中的梯子高一個單位)
利用 Vertex Snap 之功能將 "梯子碰撞機" 黏置於底端圖素原件的某一個下角
你可以複製這個物件, 改變 Y 值並黏貼到所有其它位於關卡中的梯子圖素原件上.


梯子會像這個樣子:


現在如果你按 "Play" 並控制角色移動到梯子, 這個角色應該可以在此梯子上下移動並同時配合爬的動畫. 爬到梯子頂端後可以移開, 而爬到一半就左右移動則會落回地面.

加入繩索對撞機 Collider
這裡的步驟和上一步類似.

產生一個繩索:
選擇 GameObject -> Create Other -> Cube 並將 Cube 更名為 Rope
到 Edit -> Project Setting -> Tags 以打開 "Tag manager"
在最近的可使用的空槽(可能是 Element 1) 中的 "Tags" 填入 "Rope" 並將 Layer 變更為 "NoDraw"

設定 Rope 之大小與位置:
假設你的繩索寬度為4個圖素原件:  選擇 "繩索碰撞機" 並將其 "Scale X" 值設要為 4 (Y 和 Z則為 1)
利用 Vertex Snap 之功能將 "繩索碰撞機" 黏置於底端圖素原件的某一個下角
你可以複製這個物件, 改變 X 值並黏貼到所有其它位於關卡中的 繩索 圖素原件上.


繩索會像這個樣子:

現在如果你按 "Play" 並控制角色移動到繩索 , 這個角色應該可以吊在此繩索上左右移動並同時配合吊的動畫. 此時如果暗向下的箭頭, 角色應會向下掉落.

到本階段的專案可在此下載:
http://www.rocket5studios.com/files/Rocket5_2DGame_blogPt3a.zip

如果你想要試試玩這個遊戲目前階段, 可以到以下的網址試玩 (上下左右鍵控制):
http://www.rocket5studios.com/2dgametutorial/Rocket52DGamePart3.html


本文轉載自www.rocket5studios.com,版權歸原作者所有,UnityBuster.blogspot.com整理翻譯。轉載請註明出處!

2012年5月26日 星期六

Unity3D教學 - 使用免費工具來開發2D遊戲(教學二)


本文轉載自 www.rocket5studios.com,版權歸原作者所有,UnityBuster.blogspot.com整理翻譯。轉載請註明出處!

本教學內容是要來教你如何使用一些免費的軟體工具在Unity3D中製作2D遊戲. 此一教材共分成五個部分, 連結與大綱分列於下:





使用免費工具來開發2D遊戲 - 教學一: 介紹本教學使用的工具和Unity3D的插件
使用免費工具來開發2D遊戲 - 教學二: 製作sprite(圖素原件)和第一個level(關卡)
使用免費工具來開發2D遊戲 - 教學三: 製作一個角色動畫sprite(圖素原件)並與控制腳本連結
使用免費工具來開發2D遊戲 - 教學四: 製作一個 "pickup" 物品以及計分介面並和與計分腳本連結
5: 使用 "A*尋徑" 的啟始敵人智能判斷



使用免費工具來開發2D遊戲 - 教學二

接下來我們要開始製作 "圖素原件" (sprite)和你的第一個 "關卡" (level)

專案的初步設定
在我們真正開始前, 要先進行以下的設定


設定 "Build" :
File -> Build Settings...
點選 "Web Player" 然後點選 "Switch Platform"
關閉 "Build Settings" 視窗

設定 "Player" :
Edit -> Project Settings -> Player
在 "Per-Platform Settings" 點選小地球圖 (假設在前一步選的是 Web Player )
點選 "Resolution and Presentation" 然後將 "Screen Width" 改為 800, 將 "Screen Height" 改為 600

設定 "Render" :
由於2D遊戲不會用到Unity3D的燈光系統, 所以我們只會調整環境光
Edit -> Render Settings...
點選 "Ambient Light" 後改變 color 為 (255, 255, 255, 255)


Orthello 2D 的初步設定
在 "Project" view中, 到 "Orthello -> Objects" 然後拖曳 "OT prefab" 放入 "Scene" view 或 "Hierarchy"
在 "Hierarchy", 將 OT 物件旁的小箭頭往下拉, 然後點選 "View"
將 "Pixel Perfect Resolution" 改為 800x600 (與 player設定相同)
將 "Custom Size" 改為 10

如果你現在點選 "Hierarchy" 中的 "Main Camera", 你會發現投射方式(projection)已經被設為 "Orthograph", 而 "Size" 也變成 10. 當你將OT加入scene中時, Orthello 會自動將Unity預設的 "Perspective" 改為 "Orthographic".

我個人的經驗得出的結論是: 當螢幕解析度為 800x600, 而 "Orthographic Size" 為 10 之時, 一個 比例為 1x1x1 之Cube (立方體) 在螢幕上顯示的大小剛剛好是 30 pixel (畫素), 這也剛好就是我們在建立關卡(level)時所要使用 "圖素原件" (sprite)的大小. 用來嵌合到格線中剛好.

到這一階段, 你的專案看起來應該和下圖差不多. 圖中的方型則是用來當做對比用.



製作原件圖集 (Sprite Atlas)
我們的遊戲關卡只用了幾個簡單的方塊圖: 磚塊(digable), 水泥塊 (un-digable), 梯子, 和繩索.
在此下載所需之檔案: 圖素原件檔. 下載之後解壓縮存放在你的電腦中.
執行 TexturePacker 後從 "sprites/level" 目錄中將這些 .png 圖檔拖曳到 "Sprites panel" 中.
從 "sprites/shoot" 目錄中將所有 .png 圖檔也拖曳到 "Sprites panel" 中.

Texture Settings / Layout:
將 Algorithm 設為 Basic
取銷 Trim
取銷 Enable Auto Alias

Texture Settings / Output:
保留 Data 格式為 cocos2d
在 Data File, 點選 "..." 按鈕, 看看要把這些圖素原件存在本專案的 "Asset" 目錄的哪裡. (我是存在 Assets/SpriteAtlases), 將其取名為 "level" 後點選 "Save" 儲存
TexturePacker 會將Data File的副檔名自動設為 .plist, 但由於 Unity 希望是 .xml檔, 所以我們在文字欄中將 .plist 改為 .xml.
除非有 .png 副檔我們無能為力之外, 貼圖檔路徑應該已經設成和 .xml 同一路徑了

到此, 在 TexturePacker 之畫面應類似以下圖片:

如果你現在在 TexturePacker中按下 "Publish" 並轉回 Unity3D, 你應會看到包括了原件圖集(sprite atlas) 和圖素原件檔的 "SpriteAtlases" 目錄出現在 "Project" 中.

我們還要在Unity中對原件圖集(sprite atlas) 做些改變
在 "Project" view中, 選擇 "level.png", 然後將 "Inspector" 中的 "Filter Mode" 改成 "Point"
點選 "Override for Web" 將 "Format" 改成 "Truecolor" 後, 按 "Apply"


製作關卡圖素原件 (Level Sprites)
接下來是要用 Orthello 將 "原件圖集" 轉變成 "圖素原件"(sprite)

圖素原件存放箱 (Sprite Container)
在 "Project" view中, 到 "Orthello" 目錄: Orthello -> Objects -> Sprites -> SpriteAtlas 之後將 SpriteAtlas-Cocos2D 物件拖曳放入 "Hierarchy"
在 "Hierarchy" 中, 展開 "OT" 物件以及 "Containers" 物件, 你會發現你的新存放箱 (Container" 被命名為類似 "Container (id=-6840)" 的名稱. 我們由原件圖集(sprite atlas)製作出來的 "關卡圖素原件" 將會放入此存放箱中, 你可以將其改名為, 如 "level".
從 "Project, SpriteAtlases" 目錄中將 "level.png" 拖曳並放入 "OTSprite Atlas Cocos 2D" 腳本的 "Texture" 槽中.
從 "Project, SpriteAtlases" 目錄中將 "level.xml" 拖曳並放入 "Atlas Data File" 槽中. 如果你現在將 Atlas Data 的小箭頭往下拉, 會發現已被 TexturePacker 產生之原件圖集內的資料所充滿了.

製作磚塊動畫
遊戲中當磚塊被摧毀了或重生時我們動畫來讓玩家看到變化.

從 Orthello -> Objects -> Sprites 中將 "Animation"物件拖曳放入 "Hierarchy". 如此會在 OT -> Animations 增加一個名為 "Animation (id=-4320)" 之類的新物件, 將其更名為 "level anims".
趁著OTAnimation還被選取, 依下圖更改其設定
在 Framesets 中, 將 Size 改成 3
將 "level" 物件從 OT -> Containers 中拖曳放入 Container field 以將其發佈到 Container field
從 Orthello -> Objects -> Sprites 中將 "AnimatingSprite" 物件拖曳放入"Hierarchy". 如此會在 OT -> Animations 增加一個名為 "AnimatingSprite (id=-23050)" 之類的新物件, 將其更名為 "brick".
趁著brick 物件還被選取,將 "level anims" 物件拖曳放入 "Animation" 槽, "Sprite Container" 槽會自動被一個參考到 "level" container 物件填滿


現在應可看到一個磚塊的圖素原件出現在畫面, 如果在Unity中按 "Play"即可看到動畫, 由於我們並不要在開始就播動畫, 因此取銷 "Play On Start" 之勾選

在磚塊原件加入碰撞(抗力 collision)屬性
一些磚塊需要加上抗力屬性如此角色才可以踩踏在其上

趁著brick 物件還被選取, 勾選 "Collidable" 項,   將 "Box Collider" 和 "Rigidbody" 加入圖素原件中
還要將物件標上特殊標籤並加到一個 "Layer" 中. 到 Edit -> Project Settings -> Tags 打開 "標籤管理員" (Tag Manager)
在最上方的 "Tags", 將小箭頭往下拉並在 "Element0" 欄位輸入 "Ground" 後按 Enter. 同時, 還要加入 "Ladder" 和 "Rope" 兩個標籤.
我們也需要一些 "Layer", 因此在 "User Layer 8" 輸入 "Ground", 在 "User Layer 9" 輸入 "Ladder"
點選磚塊物件後, 在 "Inspector" 拉下 "Tag" 清單並選取 "Ground", 從 "Layer" 下拉清單中點選 "Ground"

將磚塊原件變成 Prefab

接下來將新增一些東西到磚塊物件並對其做些改變. 因此將磚塊變成 "Prefab" , 而後當你用此磚塊原件來製作出關卡後, 一但你對磚塊物件做了任何變動, 該一關卡中所有的磚塊原件都會跟著改變. 製作一個 Prefab 非常簡單且會在之後為你省下許多時間.

在你的 "Project" 中產生一個新的 folder 並取名 "Prefabs"
將 "brick" 物件從 Hierarchy 中拖曳放入Project 的 Prefabs 目錄中

製作靜態的關卡圖素原件 (Level Sprites)
接下來我們需要製作水泥塊, 梯子, 和繩索方圖. 這些也同樣使用之前的存放箱 (Container). 不過不同於 AnimatedSprite 的顯示, 我們將使用圖素原件 (Sprite object).

水泥塊方圖

如果你的磚塊物件還位於畫面的中央, 請移到旁邊.
將 "Sprite" 物件從 Orthello -> Objects -> Sprites 中拖曳放入 Hierarchy 或 Scene 中, 從而會產生一個名為 "Sprite (id=-3700)" 之類的新物件, 將其更名為 "concrete"
將之前產生的 level 物件從 OT -> Containers 拖曳放入 Inspector 的 "Sprite Container" 槽中
你的Sprite會出現, 不過看起來會和之前作的磚塊原件差不多, 這是因為磚塊圖是原件圖集中的第一張圖. 選取水泥物件後, 用鼠標按住 Inspector 中的 "Frame Index"並向右拖曳到原件圖集中的14號的水泥圖案. 現在水泥物件就會是水泥外觀了.
勾選 "Collidable" 將抗力屬性加入水泥物件
下拉 Inspector 中的 Tag 清單並選取 Ground 後, 再從 Layer 的下拉清單中點選 Ground
從 Hierarchy 中將 "concrete"物件拖曳放入Project 中的 "Prefabs" 目錄因而得以由該物件產生 Prefab

梯子和繩索方圖
梯子和繩索方圖的製作步驟和水泥圖差不多:

如果你的水泥物件還位於畫面的中央, 請移到旁邊.
將 "Sprite" 物件從 Orthello -> Objects -> Sprites 中拖曳放入 Hierarchy 或 Scene 中, 將其更名為 "ladder"
將之前產生的 level 物件從 OT -> Containers 拖曳放入 Inspector 的 "Sprite Container" 槽中
將 "Frame Index"並向右拖曳到原件圖集中的15號的梯子圖案. 現在物件就會是梯子外觀了.
製作繩索物件和梯子同, 只是取名為 "rope". 將 "Frame Index"並向右拖曳到原件圖集中的17號的繩索圖案. 現在物件就會是繩索外觀了.
從 Hierarchy 中將 "ladder" 和 "rope" 物件拖曳放入Project 中的 "Prefabs" 目錄因而得以由該物件產生 Prefab

製作底部邊界
製作關卡所需的 sprite 圖素原件已經完成了, 接下來要製作一個邊界物件用來放在螢幕底邊. 這個物件提供角色和怪物站立的地方同時也提供參考格子的依據.
到 Game Object -> Create Other -> Cube 並更名為 "border bottom"
將 Transform Position 改為 X: 0, Y: -10.3, Z: 0
將 Transform Scale 改為 X: 26, Y: 1, Z: 1
將 "border bottom" 物件從 Hierarchy 中拖曳放入 Project 中的 Prefabs 目錄並將其轉成一個 prefab

有一小部分的方塊會出現在遊戲畫面底端, 由於預設的顏色是白色的, 看起來有些唐突, 我們將其改為和磚塊相似的色彩

在 Project 中產生一個新目錄並取名為 "Materials"
在 Materials 按滑鼠右鍵後到 Create -> Material 並更名新材質為 "border"
選取此一新材質然後在 Inspector 中點選小眼滴旁白色部分以打開色彩選擇器
將 RGBA 設為 R: 159, G: 2, B: 0, A: 255 後關閉
將 "border" 材質拖曳置於 Hierarchy 中的 "border bottom" 物件上將此材質賦予

改變背景顏色
將背景改為黑色:
選取 Main Camera 後 點選 Background 旁的 color swatch
將 RGBA 設為 R: 0, G: 0, B: 0, A: 255

製作關卡
最後就只剩角色, 怪物, 寶物和其他一些小東西了! 不過現階段就先將磚塊, 水泥, 梯子, 和繩索分別複製並依設計擺放到關卡中. 以下是一些注意事項:
1. 在 Scene view中, 直接點選 "Scene" 正下的下拉選單, 它或許會顯示像是 "Textured" 及更改選項到 "Tex-Wire"
2. 你可以使用 "Vertex Snap" 來對齊物件 - 在 Scene view中, 按住 "V" 鍵, 移動滑鼠讓它能圈到方塊的任一角, 這樣就會自動向最近角對齊. 當控制柄碰到Sprite之一角時按住滑鼠左鍵將sprite拖往要對齊 sprite之一角就會自動向最近角對齊
3. 你可以用螢幕底邊的邊界物件當基底來放置 sprite. 如此逐個放置就會成格狀對齊
4. 你可以 shift+left click 或 選取一個區域來多選數個 sprite.
下圖是由下往上繪製關卡的樣子

下圖則是關卡完成的樣子

本階段範例檔可在此下載: http://www.rocket5studios.com/files/Rocket5_2DGame_blogPt2b.zip


本文轉載自www.rocket5studios.com,版權歸原作者所有,UnityBuster.blogspot.com整理翻譯。轉載請註明出處!

Unity3D教學 - 使用免費工具來開發2D遊戲(教學一)

本文轉載自 www.rocket5studios.com,版權歸原作者所有,UnityBuster.blogspot.com整理翻譯。轉載請註明出處!

本教學內容是要來教你如何使用一些免費的軟體工具在Unity3D中製作2D遊戲. 此一教材共分成五個部分, 連結與大綱分列於下:






使用免費工具來開發2D遊戲 - 教學一: 介紹本教學使用的工具和Unity3D的插件
使用免費工具來開發2D遊戲 - 教學二: 製作sprite(圖素原件)和第一個level(關卡)
使用免費工具來開發2D遊戲 - 教學三: 製作一個角色動畫sprite(圖素原件)並與控制腳本連結
使用免費工具來開發2D遊戲 - 教學四: 製作一個 "pickup" 物品以及計分介面並和與計分腳本連結
5: 使用 "A*尋徑" 的啟始敵人智能判斷




使用免費工具來開發2D遊戲 - 教學一

本教學使用的工具和Unity3D的插件:

Unity3D:
本教學使用Unity3D的免費版

Orthello 2D Framework:
市面上有一些圖素原件(sprite)的插件可在Unity3D中使用, "Sprite Manager 2" 是其中之一,  而本文則是介紹  "Orthello 2D Framework" http://www.wyrmtale.com/orthello

iTween:
一個動畫的製作工具 http://itween.pixelplacement.com/index.php

A* Pathfinding Project:
一個在Unity3D中被廣為使用的尋徑系統 http://www.arongranberg.com/unity/a-pathfinding/

TexturePacker:
一個獨立的貼圖頁整合程式, 雖然你可以用其他軟體如PhotoShop來製作, 但因Orthello 2D支援 TexturePacker產生之 atlases, 因此本教學也使用它 http://www.codeandweb.com/texturepacker

在Unity3D中啟始一個新專案
1 在 File -> New Project 按選 "Set...", 選則想要存放的目錄, 輸入專案名稱後按 "Save" 後按 "Create Project" 按鈕.
2 在你的 "Project" view中產生一個新 folder 並取名 "Scenes".
3 儲存你現有的scene: 在 "File -> Save Scene As"中打開剛建好的 "Scenes", 取名 "level1" 後按 "Save"

安裝 Orthello 2D
1 開啟 Asset Store: "Window -> Asset Store", 找到 "orthello2d", 相對的頁面會出現, 點選 "Download". 也可以直接到該官網下載解壓縮後雙擊 "orthello.unitypackage"
2 當 "Import Package" 視窗出現, 先確認所有的 checkbox 都勾選後點選 "Import". 你應該會在 "Project view" 中看到 "Orthello" 目錄出現.

Orthello 2D 之基本設定
為了要讓 Orthello 在每一個 scene 中正常運作, 你必需要做幾個動作.
注意: 你每次產生一個新的  scene 時都要重覆這些步驟

在 "Project" view中, 到 "Orthello -> Objects" 然後拖曳 "OT prefab" 放入 "Scene" view 或 "Hierarchy"
"OT prefab" 在此扮演一個 "圖素原件存放箱" (Sprite Container) "動畫物件主控者" 之角色. 將"OT" 物件加入scene中也會自動改變 "Main Camara" 讓它可以在2D 遊戲中正確運作. 最主要的就是它將投射改為正交投射. (一般為透視圖視角).

安裝 iTween
1 開啟 Asset Store: "Window -> Asset Store", 找到 "itween", 相對的頁面會出現, 點選 "Download". 也可以直接到該官網下載解壓縮後雙擊 "orthello.unitypackage"
2 當 "Import Package" 視窗出現, 先確認所有的 checkbox 都勾選後點選 "Import". 你應該會在 "Project view" 中看到 " itween " 目錄出現.

安裝 A* Pathfinding
1 到該官網下載, 應會得到一個名為 "PathfindingProject_Free.unitypackage" 檔案, 雙擊該檔會在 Unity3D 中出現 "Importing Package"
2 當 "Import Package" 視窗出現, 先確認所有的 checkbox 都勾選後點選 "Import". 你應該會在 "Project view" 中看到 " AstarPathFindingProject" 目錄出現.

A* Pathfinding 之基本設定
1 到 "GameObject -> Create Empty" 以產生一個空的遊戲物件 (game object)
2 確認 x, y, z位置為 0 並更名為 "A*"
3 在 "A*" 遊戲物件加入 "Astar Path" 腳本: 到 "Component -> Pathfinding" 後點選 "Pathfinder"
4 隨著  "A*" 遊戲物件在 "Hierarchy" 中被選擇, 可以在 "Inspector" 中看到 "Astar Path script" 之選項. 在腳本之最上端, 你應該會看到 "Do you want to enable Javascript support?" 之訊息, 點選 "No" (因本教學將使用 C#)

結果
完成後產生之專案可以保留下來. 它可用來當作任何一個2D遊戲之基本樣板. 下面是完成後的畫面.


本文轉載自www.rocket5studios.com,版權歸原作者所有,UnityBuster.blogspot.com整理翻譯。轉載請註明出處!

2010年8月11日 星期三

Unity 3D Client/Server Socket Connection Sample Code


版權歸 UnityBuster.blogspot.com 所有。轉載請註明出處!
Welcome to link to this blog when referencing the article!

I'v been looking everywhere to find a socket connection sample code for Unity 3D. Although there are many sites/blogs pointed out some feature, but not a sample in whole can be found. Finally, I put some resources that I found and came out this sample. Hope those people who are looking for the answer can get one step further via this article.

You can use .net sockets to connect between Unity and socket-based applications. Furthermore, you can use most of the .net 2.0 API. If you happen to have a Unity Pro, you can write your own C++ Dlls, be noted, for the security reason, C++ Dlls can't be used with Web Player.

.NET Sockets is kind of TCP/IP Sockets. Existing network class of .NET, ex: TcpClient(client side) and TcpListener(server side), they include socket other feature support, and are easier then using Socket directly.

Below is a simple implementation. There are 2 parts: server side and client side. Server side is the Server side TcpListener code listed below. Just compile it and run it to wait for the connection. The Server was a sample code from MSDN, it can handle one Client connection at a time. As an example to make the socket connection work is enough. I'll keep on working on a simple server code that can handle multiple clients. Wish I can get it in the near future.

To do the client in the Unity, you can create a new Project, then create a JavaScript and rename to GUI_Script, copy and past the code in 'GUI_Scripts.js' listed below. When you finish this step, press left key to grab "CUI_Script" inside Unity/Project sub-window and drop on the "Main Camera" object inside Hierarchy sub-window, the script can then be attached to the Camera, you can then see the GUI when running the game. We then create a folder in the Unity/Project sub-window and rename to "Standard Assets", create a C# Script, rename it to "s_TCP", copy and past the code in the 's_TCP.cs' below. Now, run the unity game, you can try the result now.

Client side C# TCP script is attach to a GUI JavaScript. The GUI JavaScript contains a "Connect" button, a "Level 1" button, and a "Level 2" button; a text field and a "Disconnect" button. In the beginning of the game running, there is only one "Connect" button display on the screen; after the player press the button, the Unity game client will connect to the Server and establish a socket connection. The "Connect" button disappear, and the "Level 1", "Level 2" button, text filed, and "Disconnect" button show up. Whenever press the "Level 1" or "Level 2" button, the text field will use WriteSocket() function in the GUI JavaScript to send the preset string to the server, the server will then convert the lower case text to upper case text and send the result string to the client. The GUI JavaScript will then use the ReadSocket() function to read the return string and display in the text field. If you press the "Disconnect" button, the connection will be closed and the screen will change back to display "Connect" button only.



====================================================

Code listed below is for Server side TcpListener:

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;

class MyTcpListener
{
  public static void Main()
  { 
    TcpListener server=null;   
    try
    {
      // Set the TcpListener on port 13000.
      Int32 port = 13000;
      IPAddress localAddr = IPAddress.Parse("127.0.0.1");
      
      // TcpListener server = new TcpListener(port);
      server = new TcpListener(localAddr, port);

      // Start listening for client requests.
      server.Start();
         
      // Buffer for reading data
      Byte[] bytes = new Byte[256];
      String data = null;
      int counter = 0;


      // Enter the listening loop.
      while(true) 
      {
        Console.Write("Waiting for a connection... ");
        
        // Perform a blocking call to accept requests.
        // You could also user server.AcceptSocket() here.
        TcpClient client = server.AcceptTcpClient();
        counter++;
        Console.WriteLine("#"+counter+" Connected!");

        data = null;

        // Get a stream object for reading and writing
        NetworkStream stream = client.GetStream();

        int i;

        // Loop to receive all the data sent by the client.
        while((i = stream.Read(bytes, 0, bytes.Length))!=0) 
        {   
          // Translate data bytes to a ASCII string.
          data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
          Console.WriteLine("Received: {0}", data + counter);
       
          // Process the data sent by the client.
          data = data.ToUpper();

          byte[] msg = System.Text.Encoding.ASCII.GetBytes(data+"Client counter:"+counter);

          // Send back a response.
          stream.Write(msg, 0, msg.Length);
          Console.WriteLine("Sent: {0}", data + "Client counter:"+counter);            
        }
         
        // Shutdown and end connection
        client.Close();
      }
    }
    catch(SocketException e)
    {
      Console.WriteLine("SocketException: {0}", e);
    }
    finally
    {
       // Stop listening for new clients.
       server.Stop();
    }

      
    Console.WriteLine("\nHit enter to continue...");
    Console.Read();
  }   
}


====================================================

Code listed below is a C# TCP program 's_TCP.cs', which was graped from Unity Forum and made some modification:

using UnityEngine;
using System.Collections;
using System;
using System.IO;
using System.Net.Sockets;

public class s_TCP : 
MonoBehaviour {
    bool socketReady = false;

    TcpClient mySocket;
    NetworkStream theStream;
    StreamWriter theWriter;
    StreamReader theReader;
    String Host = "localhost";
    Int32 Port = 13000; 

    // Use this for initialization
    void Start() {

    }

    // Update is called once per frame
    void Update() {

    }

    public void setupSocket() {
        try {
            mySocket = new TcpClient(Host, Port);
            theStream = mySocket.GetStream();
            theWriter = new StreamWriter(theStream);
            theReader = new StreamReader(theStream);
            socketReady = true;
        }
        catch (Exception e) {
            Debug.Log("Socket error:" + e);
        }
    }

    public void writeSocket(string theLine) {
        if (!socketReady)
            return;
  String tmpString = theLine + "\r\n";
        theWriter.Write(tmpString);
        theWriter.Flush();
    }

    public String readSocket() {
        if (!socketReady)
            return "";
        if (theStream.DataAvailable)
            return theReader.ReadLine();
        return "";
    }

    public void closeSocket() {
        if (!socketReady)
            return;
        theWriter.Close();
        theReader.Close();
        mySocket.Close();
        socketReady = false;
    }
 
    public void maintainConnection(){
 if(!theStream.CanRead) {
  setupSocket();
 }
    }
} // end class s_TCP

====================================================

This is a JavaScript 'GUI_Scripts.js':

private var textFieldString = "Socket Testing String";
private var myTCP; 

function Awake() {
 myTCP = gameObject.AddComponent(s_TCP);
}

function OnGUI () {
 if(myTCP.socketReady==false) {
  if (GUI.Button (Rect (20,10,80,20),"Connect")) {
   myTCP.setupSocket();
  }
 }
 else {
  myTCP.maintainConnection();

  if (GUI.Button (Rect (20,40,80,20), "Level 1")) {
   myTCP.writeSocket(" The is from Level 1 Button");
   textFieldString=myTCP.readSocket();
  }
  if (GUI.Button (Rect (20,70,80,20), "Level 2")) {
   myTCP.writeSocket(" The is from Level 2 Button");
   textFieldString=myTCP.readSocket();
  }
  
  textFieldString = GUI.TextField (Rect (25, 100, 300, 30), textFieldString);
  
  if (GUI.Button (Rect (20,140,80,20),"Disconnect")) {
   myTCP.closeSocket();
   textFieldString = "Socket Disconnected...";
  }
 }
}

版權歸 UnityBuster.blogspot.com 所有。轉載請註明出處!
Welcome to link to this blog when reference the article!