2007年10月29日 星期一

Friendly.Flickr V2.5 released

https://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

https://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

https://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

https://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 Bank 及 New 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 控制模組的移動

https://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 模組

https://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 初試

https://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: 顯示至螢幕

遊戲最重要的觀念就是處理使用者輸入的狀況,並將結果顯示於螢幕達成與使用者互動
在這裡就是由 Update 及 Draw 兩個 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 - 微軟的野心

https://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

https://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

https://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

https://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日 星期一

令人驚艷的縮圖技術

https://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 也會加入此功能了