2007年10月29日 星期一

Friendly.Flickr V2.5 released

http://richielin-programer.blogspot.com/2007/10/friendlyflickr-v25-released.html

Friendly.Flickr 又更新了,現在到了 V2.5 版了
這一次更新讓天秤很興奮,因為這是從古早的 V2.x 版就一直想加入的功能
但是一直不知道該怎麼做,導致延到這一版才找到解決方法~
主要加上照片 GPS 座標直接在地圖上定位的功能
首先不管是修改照片或是上傳照片,在 GPS 座標頁上可以找到 [定位] 按鈕
直接按下去就對了 (上下兩個定位按鈕都是一樣的功能啦)
image

接下來就會出現以 Google Map 為基礎的地圖定位視窗
直接在地圖上找到位置後點選,或是移動地圖上圖示都可以
也可以直接輸入座標,讓你看地圖來確認該座標是否正確
完成後按確定就 OK 啦
image

另外再附加說明一些功能
1. 此視窗經緯度右側的 [定位] 按鈕,是讓你亂移動地圖後
將地圖跳回到你照片的座標的功能
2. 右下角的自訂座標點功能,預設了幾個國家的地圖位置
直接雙擊就可以以地圖中心跳到該座標點上,快速以國家或座標找點
3. 下方 [加入地圖中心點] 按鈕功能是讓你移動地圖後,將該地圖以中心點記錄在自訂座標裡
日後可以快速的切換到該地圖上
4. [加入此座標] 按鈕是把目前指定的座標記錄在自訂座標裡
5. 在自訂座標按滑鼠右鍵或是按下 Delete 鍵,可以刪去自訂座標

基本上自訂座標點是讓你將一些常去的國家或常用的景點記錄下來
當然你也可以把 Friendly.Flickr 預設的國家刪去或是加入其它的國家座標點
甚至加入台北、台中、高雄、阿里山、日月潭等座標點
以便日後要定位時可以快速的把地圖找回來

更新項目

1. 新增上傳照片及修改照片資訊,在設定 GPS 座標時可以直接在 Google Map 地圖上定位
2. 補上 GPS 座標輸入的防呆機制

檔案下載: Firendly.Flickr V2.5

2007年10月25日 星期四

Friendly.Flickr V2.4.1.1 released

http://richielin-programer.blogspot.com/2007/10/friendlyflickr-v24-released.html

先感謝大家的支持,一直給天秤很多的鼓勵和建議
這一版還是和以往一樣,優先加入最多人建議的功能 - 清單顯示
在之前的版本搜尋照片的方式為搜尋指定數量的照片
且一併秀出照片來,如下圖
image

而這一版加入了清單顯示,會一直搜尋指定條件的照片直到完成
且不下載照片及詳細的照片資訊以加快搜尋速度
對一些不想看到照片,只想要照片清單的人很有用
使用方式只有一個步驟,左下角的 [每頁張數] 選擇最後一個選項 - 清單
然後再按搜尋就行了,如下圖
image

清單模式下的操作方式和一般模式下完全相同
接下來就是看客官是要下載照片或是貼上部落格都可
如果對照片名稱和照片聯想不起來的,還可以連點二下照片來快速瀏覽照片
image

另外提出很重要一點就是
因為要加入清單模式,所以將 Friendly.Flickr 底層機制做了大變動
陸陸續續的找到一些之前未修正的問題
天秤自己也不清楚到底修正了哪些 Bug,也不清楚又搞出了什麼 Bug
所以就請大家使用時發現什麼問題再回報給天秤了~

更新項目

1. 搜尋照片新增清單顯示模式
2. 產生 KMZ 檔時,可指定是否匯入 GPX 檔中的 Track 或 Point
3. 稍微改善搜尋速度及資料的可靠性
4. Windows Live Writer Plugin 版本設定檔目錄修改原與 Friendly.Flickr 一樣,讓兩者的資料可以共用
5. 10/29 補上清單模式下按 Column 會將資料排序的功能 (V2.4.1.1) 

PS. 為加快照片搜尋速度,清單模式下並不會下載完整的照片資訊
故當在清單模式下貼上照片及資訊時,有關 [照片說明] 及 [EXIF] 資訊可能會無法正確顯示
如需以上的資訊時,請在一般模式下搜尋照片後再貼上

PS. 在清單模式下,取得別人照片的 [原始照片的位址] 可能會因為該照片設為 private 而取得失敗
請在一般模式下搜尋再重試

檔案下載: Firendly.Flickr V2.4.1.1

2007年10月19日 星期五

Friendly.Flickr V2.3.2 released

http://richielin-programer.blogspot.com/2007/10/friendlyflickr-v232-released.html

感謝許多朋友提供意見
這一版主要修正最多人提出的 - 批次下載最多下載 500 張照片的問題
基本上可以批次下載的照片數量應該是無上限了吧
應該會讓批次下載更加的完整、好用吧
其它比較小的項目,容天秤再找時間慢慢修正~

更新項目

1. 修正批次下載 Set 照片時,最大只會下載 500 張的問題
2. 搜尋 Set 照片時,修改成會依照 [每頁張數] 選項來搜尋,並可按 [上一頁] 及 [下一頁] 來換頁
3. 排版貼圖多出個 [點擊照片是否在新視窗開啟] 選項

檔案下載: Firendly.Flickr V2.3.2

2007年10月11日 星期四

XNA Game Studio Express 聲音與 XACT

http://richielin-programer.blogspot.com/2007/10/xna-game-express-xact.html

聲音是遊戲很重要的一環,聲光效果都有的遊戲才會吸引人玩下去
在 XNA Framework 中,如果要加入音樂、音效等效果
必須使用 XACT - Microsoft Cross-Platform Audio Creation Tool 來幫忙達成
以下 XNA MSDN 的範例將一步步示範如果在遊戲中加入聲音

##CONTINUE##

準備工作,使用 XACT 建立聲音專案

開啟上一篇 XNA Game Studio Express 控制模組的移動 範例中的專案
並參考 XNA Game Studio Express 顯示 3D 模組 的文章中
由先前建立的 Spacewar Windows Starter Kit 專案取出聲音檔作示範
首先在開啟專案中先建立相關目錄 Content\Audio\Waves
並 Copy Spacewar Windows Starter Kit 專案中的
Ships\engine_2.wav 及 Weapons\hyperspace_activate.wav 到此專案的相同目錄下

1. 從 Windows 開始選單,選擇 所有程式 -> Microsoft XNA Game Studio Express -> Tools,執行 Microsoft Cross-Platform Audio Creation Tool (XACT)
2. 開啟 XACT 軟體後,儲存專案在此專案的 Contant\Audio 下名稱為 MyGameAudio
3. 新增 New Wave BankNew Sound Bank,並在 Wave Bank 下加入剛才 Copy 至專案目錄下的兩個聲音檔
image

將剛才加入 Wave Bank 的兩個聲音檔,拖曳到 Sound Bank 視窗的 Cue Name Panel 中
如下所示
image

最後,指定當我們播放 engine_2 聲音時,它必須不斷環境播放
這點就像是遊戲不斷環境播放的背景音樂一樣,總不希望背景音樂只播放一次就停止了吧
Sound Bank 視窗中選擇 engine_2 聲音,並在右上方視窗選擇 Play Wave 字樣
並在視窗最左下方 LoopEvent 中選擇 Infinite 指定環境播放
image

最後儲存離開 XACT 軟體
進行到此步驟,XACT 會將我們加入的聲音檔案指定相對目錄及聲音檔的播放動作
以 MyGameAudio.xap 描述檔儲存在 Content\Audio 這個指定的目錄下
接下來就可以將 XACT project 加入示範專案的 Content Pipeline 中

加入聲音至專案

回到 Visual Studio 2005 Express 示範專案中,在 Content\Audio 目錄按右鍵
加入 -> 現有項目,選擇剛才建立的 MyGameAudio.xap
image

在 Initialize 函式下加入以下程式碼將聲音資料載入遊戲中
AudioEngine: 讀入 XACT 專案,副檔名為 .xgs
WaveBank: 取出 AudioEngine 元件中 Wave Bank 的聲音資料,副檔名為 .xwb
SoundBank: 取出 AudioEngine 元件中 Sound Bank 的聲音資料,副檔名為 .xsb

AudioEngine audioEngine;
WaveBank waveBank;
SoundBank soundBank;

protected override void Initialize()
{
    audioEngine = new AudioEngine("Content\\Audio\\MyGameAudio.xgs");
    waveBank = new WaveBank(audioEngine, "Content\\Audio\\Wave Bank.xwb");
    soundBank = new SoundBank(audioEngine, "Content\\Audio\\Sound Bank.xsb");
    base.Initialize();
}

程式中使用 Cue 物件來處理聲音播放、停止的功能
在 update 函式中判斷鍵盤輸入及決定聲音的輸出與否
需注意的是,update 函式會不斷的被呼叫,必須判斷聲音播放的狀態決定執行的動作
避免已在播放中時還不斷的要求播放,造成系統的負載

// Cue so we can hang on to the sound of the engine.
Cue engineSound = null;

protected void UpdateInput()
{
    // Get the game pad state.
    KeyboardState keyboard_currentState = Keyboard.GetState();
    if (keyboard_currentState != null)
    {
        // Rotate the model using the left thumbstick, and scale it down.
        if (keyboard_currentState.IsKeyDown(Keys.Left) == true)
            modelRotation += 1 * 0.10f;
        if (keyboard_currentState.IsKeyDown(Keys.Right) == true)
            modelRotation -= 1 * 0.10f; 

        // Create some velocity if the right trigger is down.
        Vector3 modelVelocityAdd = Vector3.Zero; 

        // Find out what direction we should be thrusting, using rotation.
        modelVelocityAdd.X = -(float)Math.Sin(modelRotation);
        modelVelocityAdd.Z = -(float)Math.Cos(modelRotation); 

        // Now scale our direction by how hard the trigger is down.
        if (keyboard_currentState.IsKeyDown(Keys.Up) == true)
            modelVelocityAdd *= 3;
        if (keyboard_currentState.IsKeyDown(Keys.Down) == true)
            modelVelocityAdd *= 0.3F; 

        // Finally, add this vector to our velocity.
        modelVelocity += modelVelocityAdd; 

        // Set some audio based on whether we're pressing a trigger.
        if (keyboard_currentState.IsKeyDown(Keys.Up) == true)
        {
            if (engineSound == null)
            {
                engineSound = soundBank.GetCue("engine_2");
                engineSound.Play();
            } 
            else if (engineSound.IsPaused)
            {
                engineSound.Resume();
            }
        }
        else
        {
            if (engineSound != null && engineSound.IsPlaying)
            {
                engineSound.Pause();
            }
        } 

        // In case you get lost, press A to warp back to the center.
        if (keyboard_currentState.IsKeyDown(Keys.Space) == true)
        {
            modelPosition = Vector3.Zero;
            modelVelocity = Vector3.Zero;
            modelRotation = 0.0f; 

            // Make a sound when we warp.
            soundBank.PlayCue("hyperspace_activate");
        }
    } 

    // Get the game pad state.
    GamePadState currentState = GamePad.GetState(PlayerIndex.One);
    if (currentState.IsConnected)
    {
        // Rotate the model using the left thumbstick, and scale it down.
        modelRotation -= currentState.ThumbSticks.Left.X * 0.10f; 

        // Create some velocity if the right trigger is down.
        Vector3 modelVelocityAdd = Vector3.Zero; 

        // Find out what direction we should be thrusting, using rotation.
        modelVelocityAdd.X = -(float)Math.Sin(modelRotation);
        modelVelocityAdd.Z = -(float)Math.Cos(modelRotation); 

        // Now scale our direction by how hard the trigger is down.
        modelVelocityAdd *= currentState.Triggers.Right; 

        // Finally, add this vector to our velocity.
        modelVelocity += modelVelocityAdd; 

        GamePad.SetVibration(PlayerIndex.One, currentState.Triggers.Right,
            currentState.Triggers.Right); 

        // Set some audio based on whether we're pressing a trigger.
        if (currentState.Triggers.Right > 0)
        {
            if (engineSound == null)
            {
                engineSound = soundBank.GetCue("engine_2");
                engineSound.Play();
            } 
            else if (engineSound.IsPaused)
            {
                engineSound.Resume();
            }
        }
        else
        {
            if (engineSound != null && engineSound.IsPlaying)
            {
                engineSound.Pause();
            }
        } 

        // In case you get lost, press A to warp back to the center.
        if (currentState.Buttons.A == ButtonState.Pressed)
        {
            modelPosition = Vector3.Zero;
            modelVelocity = Vector3.Zero;
            modelRotation = 0.0f; 

            // Make a sound when we warp.
            soundBank.PlayCue("hyperspace_activate");
        }
    }
}

原本 XNA MSDN 範例中以 XBOX360 為示範平台
天秤將它改成以 PC 鍵盤輸入操作及聲音輸出
範例中按下上鍵時飛行器會加速,並發出加速的聲音,由於 engine_2 聲音在 XACT 中被指定為不斷播放,所以按住上鍵時會持續的播放直到放開
按下 Space 鍵時飛行器會回到預設值,並發出 hyperspace_activate 聲音

下載: 本範例程式碼及執行檔下載

XNA Game Studio Express 控制模組的移動

http://richielin-programer.blogspot.com/2007/10/xna-game-express_11.html

繼前幾篇文章 XNA Game Studio Express 初試 中示範 2D 遊戲畫面顯示
XNA Game Studio Express 顯示 3D 模組 中對示範 3D 遊戲畫面顯示
都還只是顯像輸出的範圍,遊戲中很重要的一項因素 - 互動
當然得包含輸出及輸入部份
本範例將介紹輸入的部份,還是以 XNA MSDN 上範例做示範
但由於該範例是以 XBOX360 控制器做為輸入界面,無法在 PC 上實際操控
所以天秤將稍微修改一下範例,以鍵盤當成輸入界面,使其在 PC 上可以動作

##CONTINUE##

準備工作

本範例是延續上一篇文篇的範例,直接跳至此篇的朋友
可以下載上一篇文章範例的程式碼來學習

讀取輸入裝置

前幾篇文章陸陸續續有提到,GraphicsDeviceManager 類別兩個重要的函式
draw 函式負責不斷的將畫面輸出至螢幕
而 update 函式即是負責不斷的計算、處理遊戲中的參數,如處理使用者的輸入
此範例即是在 update 函式加入判斷輸入的功能
其中有關 GamePad 物件為 XBOX360 特有的物件,用來取得 XBOX360 搖捍的輸入狀態
Keyboard 物件即為取得 PC 上鍵盤輸入的物件
而判斷某鍵是否有輸入,可以 Keyboard.GetState() 函式取得鍵盤狀態中該鍵是否有按下
再依是否按下狀態來做模組的移動

// Set the velocity of the model, applied each frame to the model's position.
Vector3 modelVelocity = Vector3.Zero;

protected override void Update(GameTime gameTime)
{
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
        this.Exit();
    if (Keyboard.GetState().IsKeyDown(Keys.Escape) == true)
        this.Exit(); 

    // Get some input.
    UpdateInput(); 

    // Add velocity to the current position.
    modelPosition += modelVelocity; 

    // Bleed off velocity over time.
    modelVelocity *= 0.95f; 

    base.Update(gameTime);
}

protected void UpdateInput()
{
    // Get the game pad state.
    KeyboardState keyboard_currentState = Keyboard.GetState();
    if (keyboard_currentState != null)
    {
        // Rotate the model using the left thumbstick, and scale it down.
        if (keyboard_currentState.IsKeyDown(Keys.Left) == true)
            modelRotation += 1 * 0.10f;
        if (keyboard_currentState.IsKeyDown(Keys.Right) == true)
            modelRotation -= 1 * 0.10f; 

        // Create some velocity if the right trigger is down.
        Vector3 modelVelocityAdd = Vector3.Zero; 

        // Find out what direction we should be thrusting, using rotation.
        modelVelocityAdd.X = -(float)Math.Sin(modelRotation);
        modelVelocityAdd.Z = -(float)Math.Cos(modelRotation); 

        // Now scale our direction by how hard the trigger is down.
        if (keyboard_currentState.IsKeyDown(Keys.Up) == true)
            modelVelocityAdd *= 2;
        if (keyboard_currentState.IsKeyDown(Keys.Down) == true)
            modelVelocityAdd *= 0.5F; 

        // Finally, add this vector to our velocity.
        modelVelocity += modelVelocityAdd; 

        // In case you get lost, press A to warp back to the center.
        if (keyboard_currentState.IsKeyDown(Keys.Space) == true)
        {
            modelPosition = Vector3.Zero;
            modelVelocity = Vector3.Zero;
            modelRotation = 0.0f;
        }
    } 

    // Get the game pad state.
    GamePadState currentState = GamePad.GetState(PlayerIndex.One);
    if (currentState.IsConnected)
    {
        // Rotate the model using the left thumbstick, and scale it down.
        modelRotation -= currentState.ThumbSticks.Left.X * 0.10f; 

        // Create some velocity if the right trigger is down.
        Vector3 modelVelocityAdd = Vector3.Zero; 

        // Find out what direction we should be thrusting, using rotation.
        modelVelocityAdd.X = -(float)Math.Sin(modelRotation);
        modelVelocityAdd.Z = -(float)Math.Cos(modelRotation); 

        // Now scale our direction by how hard the trigger is down.
        modelVelocityAdd *= currentState.Triggers.Right; 

        // Finally, add this vector to our velocity.
        modelVelocity += modelVelocityAdd; 

        GamePad.SetVibration(PlayerIndex.One, currentState.Triggers.Right,
            currentState.Triggers.Right); 

        // In case you get lost, press A to warp back to the center.
        if (currentState.Buttons.A == ButtonState.Pressed)
        {
            modelPosition = Vector3.Zero;
            modelVelocity = Vector3.Zero;
            modelRotation = 0.0f;
        }
    }
}

本範例可以輸入鍵盤左、右鍵來控制飛行器的左右旋轉
上、下鍵來控制飛行器速度,如果飛行器飛出螢幕範圍了
按下 Space 鍵可以回復預設值,讓飛行器再次回到螢幕中央
最後按下 Escape 鍵結束

下載: 本範例程式碼及執行檔下載

2007年10月10日 星期三

XNA Game Studio Express 顯示 3D 模組

http://richielin-programer.blogspot.com/2007/10/xna-game-express-3d.html

image

繼上一篇 XNA Game Studio Express 初試 之後,對 XNA 架構愈來愈感興趣了
能以簡單易學易用的 .NET Framework 架構來撰寫遊戲實在是方便
接下來還是以 XNA MSDN 上範例來學習如何在遊戲中顯示 3D Model
3D 這應該是目前遊戲界的重頭戲了,且看以 XNA 如何快速的撰寫 3D 遊戲

##CONTINUE##

準備工作

因為此範例需要 3D 模組及紋理,所以必須先建立 Spacewar Windows Starter Kit 這專案
建立完成後即可儲存關閉,因為此範例只是運用該專案目錄下的模組來示範
image

開啟 Windows Game 範本的新專案,並在 方案總管 按右鍵 新增資料夾 上加入以下的目錄
按右鍵 新增現有項目,將 p1_wedge.fbx 檔案加入
並手動將 Textures\wedge_p1_diff_v1.tga Copy 到本專案的 Textures 目錄下
PS. p1_wedge.fbx 模組有需要有 wedge_p1_diff_v1.tga 圖檔當作紋理
但 p1_wedge.fbx 會自己至相對應目錄下取得 wedge_p1_diff_v1.tga
因專案不需使用此圖檔 (只有該模組使用),故只將該檔 Copy 到 Textures 目錄下即可
無需加入專案的 Content Pipeline 內
image

開始寫程式吧

首先當然是讀取 3D 模組等資源,和上個範例相同
在 LoadGraphicsContent 函式撰寫讀取資源的程式碼

// Set the 3D model to draw.
Model myModel;

// The aspect ratio determines how to scale 3d to 2d projection. float aspectRatio;

protected override void LoadGraphicsContent(bool loadAllContent)
{
    if (loadAllContent)
    {
        myModel = content.Load<Model>("Content\\Models\\p1_wedge");
    } 

    aspectRatio = graphics.GraphicsDevice.Viewport.Width / graphics.GraphicsDevice.Viewport.Height;
}

在 Draw 函式內顯示出該 3D 模組,其中
World: 控制模組在遊戲世界中的位置
View: 控制遊戲中攝影機在遊戲世界的位置及攝影的方向,相對於使用者看到世界
Projection: 控制遊戲中如果將 3D 世界以 2D 方式呈現出來 (螢幕)

// Set the position of the model in world space, and set the rotation.
Vector3 modelPosition = Vector3.Zero;
float modelRotation = 0.0f;

// Set the position of the camera in world space, for our view matrix.
Vector3 cameraPosition = new Vector3(0.0f, 50.0f, 5000.0f);

protected override void Draw(GameTime gameTime)
{
    graphics.GraphicsDevice.Clear(Color.CornflowerBlue); 

    // Copy any parent transforms.
    Matrix[] transforms = new Matrix[myModel.Bones.Count];
    myModel.CopyAbsoluteBoneTransformsTo(transforms);     // Draw the model. A model can have multiple meshes, so loop.
    foreach (ModelMesh mesh in myModel.Meshes)
    {
        // This is where the mesh orientation is set, as well as our camera and projection.
        foreach (BasicEffect effect in mesh.Effects)
        {
            effect.EnableDefaultLighting();
            effect.World = transforms[mesh.ParentBone.Index] * Matrix.CreateRotationY(modelRotation)
                * Matrix.CreateTranslation(modelPosition);
            effect.View = Matrix.CreateLookAt(cameraPosition, Vector3.Zero, Vector3.Up);
            effect.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f),
                aspectRatio, 1.0f, 10000.0f);
        }
        // Draw the mesh, using the effects set above.
        mesh.Draw();
    }
}
動起來吧

在 update 函式裡,我們可以加上一些程式碼,讓飛行器的定時旋轉
只要改變 modelRotation 參數
讓 draw 函式被呼叫,計算 effect.World 時能依我們的參數改變模組的角度

protected override void Update(GameTime gameTime)
{
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
        this.Exit(); 

    modelRotation += (float)gameTime.ElapsedGameTime.TotalMilliseconds * MathHelper.ToRadians(0.1f); 

    base.Update(gameTime);
}

按下 F5 編譯執行,執行結果如下
遊戲畫面為一台 3D 飛行器,隨著時間不斷的原地旋轉著
image

顯示 3D 模組比 2D 複雜一些
但是 XNA Framework 有效的提供了一些元件供簡單的呼叫來顯示 3D 模組
範例其中有數個參數都可以決定顯示出的結果,各有各的重要性
建議新接觸 XNA 的人可以嘗試著修改一些參數,看執行結果會有什麼變化

下載: 本範例程式碼及執行檔下載

2007年10月9日 星期二

XNA Game Studio Express 初試

http://richielin-programer.blogspot.com/2007/10/xna-game-express_09.html

image
系統需求

Windows XP SP2 及 Vista 各版本 (看來 Microsoft 已徹底放棄 Windows 2000 了)
支援 Shader Model 1.1 及至少支援 DirectX 9.0c 的圖形界面卡

檔案下載

Visual Studio 2005 Express Editions 及 SP1
Microsoft XNA Game Studio Express 1.0 Refresh
.NET Framework 2.0
.NET Framework 1.1

##CONTINUE##

基本觀念

開啟 Windows Game 範本的新專案,一些繁瑣的前置作業都由 XNA 做好了
包含已建立最重要的螢幕顯示物件 GraphicsDeviceManager ,及以下五個主要的事件

  • Initialize: 初始化遊戲中任何與 Graphics 無關的資源,如設定、遊戲進度等資料
  • LoadGraphicsContent: 載入 Graphics 相關的資源,如模組、圖示等
  • UnloadGraphicsContent: 釋放載入的 Graphics 資源
  • Update: 處理、計算每個 Frame 要顯示的狀態,或做些程式判斷等動作
  • Draw: 顯示至螢幕

遊戲最重要的觀念就是處理使用者輸入的狀況,並將結果顯示於螢幕達成與使用者互動
在這裡就是由 UpdateDraw 兩個 Event 來負責處理輸入、運算及顯示輸出

第一個遊戲

這裡以 Microsoft 官網 MSDN 上範本來測試
在螢幕上貼上一個圖檔
以上一步產生的新專案為例,就直接顯示 GameThumbnail.png 這個新專案內建圖檔好了
但必須注意須將 GameThumbnail.png 的 XNA Framework Content 屬性設為 True
才會將 GameThumbnail.png 加入 XNA Content Pipeline 內讓程式可以呼叫使用

// This is a texture we can render.
Texture2D myTexture;

// Set the coordinates to draw the sprite at.
Vector2 spritePosition = Vector2.Zero;

// This is the object that will draw the sprites.
SpriteBatch spriteBatch;

protected override void LoadGraphicsContent( bool loadAllContent )
{
    if (loadAllContent)
    {
        myTexture = content.Load<Texture2D>("GameThumbnail");
        spriteBatch = new SpriteBatch(graphics.GraphicsDevice);
    }
}
protected override void Draw(GameTime gameTime)
{
    graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

    // Draw the sprite.

    spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
    spriteBatch.Draw(myTexture, spritePosition, Color.White);
    spriteBatch.End();

    base.Draw(gameTime);
}

加入程式碼後,按 F5 執行
遊戲畫面顯示如下,左上角為載入並顯示的圖檔
image

來吧! 加入移動及碰撞

我們之前有提到過,update 函式是用來處理輸入及運算用的
這是個會不斷被呼叫的 Event ,透過每次呼叫該函式來處理計算一些事情後
讓 draw 函式可以顯示正確的畫面
以本範例來說,可以在 update 被呼叫時將圖示移動固定位置並判斷是否碰到視窗邊緣
讓下次 draw 函式被呼叫時可以將圖示顯示在正確位置上


// Store some information about the sprite's motion.
Vector2 spriteSpeed = new Vector2(50.0f, 50.0f);

protected override void Update(GameTime gameTime)
{
    // Allows the default game to exit on Xbox 360 and Windows.
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
        this.Exit(); 

    // Move the sprite around.
    UpdateSprite(gameTime); 

    base.Update(gameTime);
}

void UpdateSprite(GameTime gameTime)
{
    // Move the sprite by speed, scaled by elapsed time.
    spritePosition += spriteSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;

    int MaxX = graphics.GraphicsDevice.Viewport.Width - myTexture.Width;
    int MinX = 0;
    int MaxY = graphics.GraphicsDevice.Viewport.Height - myTexture.Height;
    int MinY = 0; 

    // Check for bounce.
    if (spritePosition.X > MaxX)
    {
        spriteSpeed.X *= -1;
        spritePosition.X = MaxX;
    } 
    else if (spritePosition.X < MinX)
    {
        spriteSpeed.X *= -1;
        spritePosition.X = MinX;
    }

    if (spritePosition.Y > MaxY)
    {
        spriteSpeed.Y *= -1;
        spritePosition.Y = MaxY;
    }
    else if (spritePosition.Y < MinY)
    {
        spriteSpeed.Y *= -1;
        spritePosition.Y = MinY;
    }
}

按 F5 後的執行結果如下
圖示會不斷的移動,當碰到視窗邊緣時即返回
image

當然寫個遊戲不是那麼簡單的事
本篇參考 Microsoft XNA MSDN 的範例可以改善的東西太多,如流暢度、聲音、輸入界面等
但本範例倒是很適合剛接觸 XNA 開發遊戲的人,分享出來與朋友共同成長
天秤之前也沒碰過 XNA 及 DirectX,只在 PPC 上寫過小遊戲 - 旋轉泡泡球 PPC 版
雖然使用的元件不同、平台不同,但概念卻相同
寫程式不也是如此,觀念正確就一通百通~

下載: 本範例程式碼及執行檔下載

2007年10月8日 星期一

XNA Game Express - 微軟的野心

http://richielin-programer.blogspot.com/2007/10/xna-game-express.html

微軟推出 XBOX360 目前已售出千萬台了
除了日本之外,其餘國家的接受度非常高,銷售成績也很好
主要原因為 XBOX360 效能很好,遊戲開發平台優異,加上了一堆原因
然而遊戲開發平台的優異是眾所皆知的,但微軟的目標不只於此

免費的 XNA Game Express 專案就是一個野心
它是一個跨 PC 與 XBOX360 的遊戲開發工具
以 XNA 在 PC 上開發遊戲及販賣都不需付費,但在 XBOX360 上必須付年費,但價格不高
憑藉著多年 Visual Studio 打下的基礎及 .Net Framework 及 C# 簡單易開發的特性
企圖打造個一魚多吃的境界,想想看以下情況

1. 當別的平台的遊戲開發業者開發的遊戲想跨最多人使用的 PC 平台
如果以 XNA 開發完成後,不只可以在 PC 上販賣遊戲,連 XBOX360 上也幾乎一併完成
多了個遊戲平台增加收入,何樂不為
2.遊戲相關科系單位以 XNA 教學,有效率且有系統 (目前美國多所大學已採用 XNA 教學)
這些學生日後都是 Windows 平台及 XBOX360 系統的潛在開發者
3. 一些程式設計師或有興趣的人都可以無條件的下載免費的 XNA 來玩
只要其中有 1/10000 的人玩出心得來了
都可以為 Windows or XBOX360 多一堆優秀的遊戲開發者
4. 優秀且免費的 XNA 開發平台,愈來愈多人有興趣且接觸之下
會吸引一些人才為其開發一堆引擎、套件等工具
這些都會讓 XNA 開發平台愈來愈強大,愈來愈易開發,吸引愈多人接觸
不斷的良性循環...

這些都是微軟遊戲快速向下札根的方式,也是日後微軟遊戲帝國的根基
當一家遊戲公司有資金 (超有錢),有技術,有人力為其開發遊戲
很難想像當它茁壯到一定程度,還有誰能與它競爭?

2007年10月4日 星期四

免費的虛擬光碟軟體 Alcohol 52% Free Edition

http://richielin-programer.blogspot.com/2007/10/alcohol-52-free-edition.html

隨著硬碟空間愈來愈來大,CD or DVD 光碟的容量與之相比愈顯得微不足道
甚至換片的不方便性及較慢的讀取速度愈來愈讓人不能忍受了
而虛擬光碟這種概念即是很好的解決方案

酒精 Alcohol 120% 是許多人使用的燒錄、虛擬光碟軟體
也有許多人只拿來當虛擬光碟用 (像天秤就是)
現在製作 Alcohol 120% 軟體的公司,拿掉了燒錄光碟的部份
推出個免費的虛擬光碟軟體 Alcohol 52% Free Edition

官方網站: Alcohol
軟體下載: Alcohol 52% Free Edition

免費版本的 Alcohol 52% Free Edition 最大支援 6 個虛擬光碟裝置 (應該夠用了)
25 種語言 (包含繁體中文)
CD 支援格式: CD-DA, CD+G, CD-ROM, CD-XA, Video CD, Photo CD, Mixed Mode, Multi-session CD
DVD 支援格式: DVD-ROM, DVD-Video, DVD-Audio
但必須注意的是,無法與 Alcohol 120% 並存在同一台電腦上
不過既然已安裝 Alcohol 120% 了,當然也不需要安裝 Alcohol 52% Free Edition
所以也不算缺點了吧

2007年10月3日 星期三

Excel 2007 Bug

http://richielin-programer.blogspot.com/2007/10/excel-2007-bug.html

天秤上個禮拜在網路上亂逛,就曾看到這個 Excel Bug 的消息了
只不過當時沒特別注意,只覺得管它的
反正天秤又不常用 Excel,也沒覺得有什麼大不了的

今天無聊時又想到了,剛好天秤也是安裝 Excel 2007
於是就來試了一下,還真的耶~
先用計算機得知 850 * 77.1 應該會得到 65535
但在 Excel 只要輸入 =SUM(850*77.1) 竟然會顯示 100000
於是天秤又試了其它運算式,不管是
=SUM(85*771) 或是 =SUM(8500*7.71) 都正確
就只有 =SUM(850*77.1) 顯示錯誤了,夠誇張了

不過如果輸入 =SUM((850*77.1)/65535) 則又會顯示正確的值 1
這表示這個 Bug 應該只是顯示錯誤,而不是運算錯誤
還好還好,如果是運算錯誤那代誌就超大條了
代表使用者不小心運算式中剛好有這個條件就完蛋了
不過光這個 Bug 應該也會讓 Microsoft 灰頭土臉了吧
就看 Microsoft 怎麼危機處理了

2007年10月2日 星期二

Friendly.Flickr V2.3.1.1 released

http://richielin-programer.blogspot.com/2007/10/friendlyflickr-v23-released.html

感謝 Mobile01 上網友 cjc_298 的建議
剛好有一些時間,於是將 Friendly.Flickr 加入了照片資訊修改的功能了
在 Flickr 上可以修改的項目很多
但是目前只加入修改標題、標籤、說明、權限、座標、群組的功能
及取代照片的功能 (這個功能很好用哦),其實應該也夠用了啦
如果想修改其它的項目,就請按照片右鍵 -> 瀏覽此照片
到 Flickr 網站上以網頁修改了
也許某天心血來潮,再來加上其它功能好了

更新項目

1. 修正 Urmap 及 Vitrual map 的連結
2. 加入修改照片資訊的功能 - 標題、標籤、說明、座標、群組、取代此照片
3. 自動儲存未上傳完成的照片

檔案下載: Firendly.Flickr V2.3.1.1

操作說明

點下右邊多出來的按鈕,就會開啟修改照片的視窗
image

拖曳照片到新視窗,只能拖曳自己的照片
選擇照片並輸入新的照片資訊
image

值得一提的如果上傳的照片錯誤,可以在此頁重新上傳照片
image

最後按下 [確定修改] 按鈕,等待修正完成即可
照片修改後,記得必須已在顯示中的照片資訊是不會跟著更新的
必須重新搜尋一遍,才會更新新的照片資訊
image

順便一提的是,前幾版本就有的刪除照片功能也許很多人都還不知道
只要在搜尋照片後,在主視窗的照片上按下右鍵選單 -> [刪除 Flickr 上的照片即可]
但只能刪除自己的照片哦
image

PS. 10/04 懶得再寫一篇文章,於是偷偷的更新一下版號成 V2.3.1
多加入了自動儲存未上傳完成的照片
在上傳視窗的照片及標題、標籤等資訊,只要未成功上傳至 Flickr
就算關閉軟體了也沒關係,下次開啟時還會保留著
但須注意的是硬碟上該照片必須還保留著才行

PS. 10/11 再偷偷更新一版本 V2.3.1.1
修正輸入兩個以上標籤時,上傳後標籤會錯誤的問題

2007年10月1日 星期一

令人驚艷的縮圖技術

http://richielin-programer.blogspot.com/2007/10/blog-post.html

最近發現幾篇介紹新的縮圖技術文章
Piggyworld Blog 的「驚人、新一代的縮圖(resize)|rsizr
電腦玩物 的「Rsizr智慧型在線縮圖服務之驚奇試玩筆記
對其中縮圖技術驚奇不已,相信這絕對是未來各繪圖軟體必備的縮圖技術了

官方網站 rsizr:http://rsizr.com/
該網站是以 Flash 製作,無須註冊即可直接使用
提供 JPG、PNG、GIF 格式圖片上傳,除了一般的縮圖、裁切之外
最重要也最讓人驚艷的是新的縮放技術 (不知道該縮放技術中文怎麼說)
該技術簡單的說就是以演算法,將圖片縮小時不會影響到圖片中物件的比例
也可以特意保留或刪去圖片中某個物件,而不影響到圖片顯示的效果

天秤試玩了一下,發現效果顯著且直覺,不過大概是以 Flash 製作的關係,速度不快
建議不要以太大的圖片測試,下面是天秤試玩的效果

測試一: 寬景製作
原比例縮圖: 500x313
 image

直接縮圖的寬景效果 500x156,長寬比例全不對了
image

裁切製作的寬景效果 500x156,為了保留地面物件,只能犧牲天空了
image

Rsizr 製作的寬景效果 500x156,照片上物件都保待原本比例
視覺效果比原圖更強烈~ 只能以驚艷形容~
 image

測試二: 去除物件效果
去除照片中心那個招牌效果,一樣效果驚人
image

測試三: 保留物件效果
保留照片中心那個招牌和文字部份,可以和原圖比對招牌大小
照片已縮小了,但是招牌大小和原圖幾乎一致
image

滿驚人的一項技術,且操作簡單實用,效果令人驚艷
讓人十分期待此技術在繪圖軟體上的實作
也許下一版本 PhotoShop 或 Lightroom 也會加入此功能了