2009年6月30日 星期二

AS3如何複製DisplayObject

最近正在寫一個FLASH的相片大頭貼截取程式,碰到了一個複製MovieClip的問題,AS3已經沒有AS2的duplicateMovie()方法可以用,所以我找了一些解決方法分享上來。


第一種方式是比較好的解決方法,是PTT的CJCAT大提供的,可以直接複製一個相同的Class。
假如場景上面有一個clip_mc,它的class是MyClip,在不使用 new MyClip() 的前提下,以下的code可以生出一個新的MyClip物件。
// 先抓到MyClip的constructor
var mcClass:Class = Object(clip_mc).constructor;
 
// 這樣就生出一個新的MyClip物件了
var clip2_mc:DisplayObject = new mcClass();
 
// 加入到舞台後就成功了
this.addChild(clip2_mc);

不過上面這個方法我試不出來,不知道是不是哪裡出錯了,所以又找了第二種方法,Copying a Sprite using BitmapData,這個方法可以將Sprite的畫面複製到另一個DisplayObject上,因為我只是需要複製一個靜態的圖,所以可以不需要使用第一種複製Class的方式。

// 先實體一個clip_mc大小的BitmapData
var myBitmapData:BitmapData = new BitmapData(clip_mc.width, clip_mc.height);
// 然後繪製一個相同的clip_mc
myBitmapData.draw(clip_mc);
 
// 實體一個複製的Bitmap
var clip2_mc:Bitmap = new Bitmap(myBitmapData);
 
// 加入到舞台後就成功了
this.addChild(clip2_mc);

參考資料:

2009年6月12日 星期五

XNA Simple Animation

因為我的大學專題是寫一款四人網路連線的格鬥遊戲,所以對XNA這套微軟提供的遊戲開發平台有點研究,之前在痞客邦寫網誌的時候有寫過幾篇這個作品的開發情況,後來因為實在太忙了所以沒有繼續介紹下去,現在這個遊戲已經在去年完成了,也得到不錯的成績,有機會我會PO上來分享一些製作心得。
在網誌搬到Blogger之後一直沒有機會寫一些跟XNA有關的文章,我打算介紹一些XNA Creators Club教學範例中所使用到的開發技術,國內介紹XNA的文章不多,有興趣用XNA開發遊戲的人,推薦可以到點部落去看一些不錯的文章。


這一篇我想先介紹XNA如何使用Model、ModelBone和ModelMesh等技術去載入一個3D模型,然後控制一些簡單的3D動畫。

首先必須先準備一個3D模型,XNA預設的類型有.x跟.fbx兩種模型檔,這裡我們先用微軟提供的坦克車模型(part1)(part2)來作示範。

一開始先建立一個XNA的專案。


將模型檔加入到Content資料夾內。


新增一個Tank.cs:
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
 
namespace SimpleAnimationSample
{
/// <summary>
/// 能讓零件動作的坦克車模型類別
/// </summary>
public class Tank
{
/// <summary>
/// 坦克車模型
/// </summary>
private Model tankModel;
 
/// <summary>
/// 坦克所有組件的平移矩陣
/// </summary>
private Matrix[] boneTransforms;
 
/// <summary>
/// 載入坦克車資源
/// </summary>
public void Load(ContentManager content)
{
// 從ContentManager載入坦克車模型.
this.tankModel = content.Load<Model>("tank");
 
// 配置所有組件的平移矩陣
this.boneTransforms = new Matrix[this.tankModel.Bones.Count];
}

/// <summary>
/// 坦克車的繪圖機制
/// </summary>
/// <param name="world">世界矩陣</param>
/// <param name="view">觀察矩陣</param>
/// <param name="projection">投影矩陣</param>
public void Draw(Matrix world, Matrix view, Matrix projection)
{
// 設定坦克車最上層的平移矩陣為世界矩陣
this.tankModel.Root.Transform = world;
 
// 更新所有組件的平移矩陣
this.tankModel.CopyAbsoluteBoneTransformsTo(this.boneTransforms);
 
// 繪製模型
foreach (ModelMesh mesh in this.tankModel.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.World = this.boneTransforms[mesh.ParentBone.Index];
effect.View = view;
effect.Projection = projection;
 
effect.EnableDefaultLighting();
}
 
mesh.Draw();
}
}
}
}
修改遊戲主程式Game1.cs(這裡我命名為SimpleAnimation.cs):
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
 
namespace SimpleAnimationSample
{
/// <summary>
/// 控制坦克車模型動畫的範例程式
/// </summary>
public class SimpleAnimation : Microsoft.Xna.Framework.Game
{
private GraphicsDeviceManager graphics;
 
private Tank tank;

public SimpleAnimation()
{
this.graphics = new GraphicsDeviceManager(this);
 
this.graphics.PreferredBackBufferWidth = 600;
this.graphics.PreferredBackBufferHeight = 450;
 
this.Content.RootDirectory = "Content";
}
 
/// <summary>
/// 初始化遊戲內容
/// </summary>
protected override void Initialize()
{
this.tank = new Tank();
 
base.Initialize();
}
 
/// <summary>
/// 載入遊戲資源
/// </summary>
protected override void LoadContent()
{
this.tank.Load(this.Content);
}
 
/// <summary>
/// 遊戲繪圖更新
/// </summary>
/// <param name="gameTime">上一次繪圖後經過的時間</param>
protected override void Draw(GameTime gameTime)
{
this.GraphicsDevice.Clear(Color.CornflowerBlue);
 
// 視窗畫面
Viewport viewport = this.GraphicsDevice.Viewport;
 
// 畫面長寬比
float aspectRatio = (float)viewport.Width / (float)viewport.Height;
 
// 世界矩陣(縮放矩陣, 旋轉矩陣, 平移矩陣)
Matrix world = Matrix.CreateScale(1.0f) * Matrix.CreateRotationY(MathHelper.PiOver4) * Matrix.CreateTranslation(Vector3.Zero);
 
// 觀察矩陣(攝影機座標, 攝影機焦點座標, 攝影機上方的向量)
Matrix view = Matrix.CreateLookAt(new Vector3(1000, 600, 0), new Vector3(0, 100, 0), Vector3.Up);
 
// 投影矩陣(畫面視角呈現弧度, 畫面長寬比, 近景值, 遠景值)
Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, aspectRatio, 10, 10000);
 
this.tank.Draw(world, view, projection);
 
base.Draw(gameTime);
}
}
}

執行結果: