電腦遊戲製作開發設計論壇 首頁 電腦遊戲製作開發設計論壇
任何可以在PC上跑的遊戲都可以討論,主要以遊戲之製作開發為主軸,希望讓台灣的遊戲人有個討論、交流、教學、經驗傳承的園地
 
 常見問題常見問題   搜尋搜尋   會員列表會員列表   會員群組會員群組   會員註冊會員註冊 
 個人資料個人資料   登入檢查您的私人訊息登入檢查您的私人訊息   登入登入 

Google
[XNA] vol 2.5 SpriteFormat 介紹... (未完成)

 
發表新主題   回覆主題    電腦遊戲製作開發設計論壇 首頁 -> 遊戲程式高級班:DirectX、OpenGL及各種圖型函式庫
上一篇主題 :: 下一篇主題  
發表人 內容
babu61509
散播福音的祭司


註冊時間: 2007-08-26
文章: 142

681.01 果凍幣

發表發表於: 2007-10-26, PM 8:25 星期五    文章主題: [XNA] vol 2.5 SpriteFormat 介紹... (未完成) 引言回覆

這是一個我自己寫的小Class,方便 SpriteBatch 的 Draw 函數用。

裡面除了包含了必要的 Draw 用傳入值,還有自動切換圖片和方框碰撞功能,雖然寫的不算很好,不過也不錯用了!

我會用這個Class來介紹 Draw 函數還有跟大家說怎麼切換圖片和判斷方框碰撞。

note : Class程式碼在最後面.
------------------------------------------------------------------ [SpriteFormat結構簡介]

先來介紹 FrameFormat 的結構如下 :
代碼:

public struct FrameFormat
  |
  |----- public int Width; // Frame 寬度
  |----- public int Height; // Frame 高度
  |----- public int MaxFrame;  // Frame 最大值
  |----- public int NowFrame;  // 現在的 Frame
  |----- public int MinFrame;  // Frame 最小值
  |----- public int FramePerSecond;  // 每秒顯示幾張 Frame
  |----- public Boolean AutoChange;  // 是否自動更新 Frame

這個代表 Frame 的資料,程式會根據 Frame 的資料來更新顯示.

note : 連環圖就是由許多 Frame 組成的,例如走路、跳等等連續的動作,這裡我用的是將一個動作連環圖 Frame 放在一張圖片,再根據這個設定來切換.

SpriteFormat 的結構如下 :
代碼:

public class SpriteFormat
  |
  |----- public Vector2 Location;  // Sprite 位置
  |----- public Rectangle sourceRectangle;  // Sprite 取得圖檔內位置及大小
  |----- public Vector2 Center;  // Sprite 中心點
  |----- public float Rotation;  // Sprite 旋轉弧度
  |----- public float RotationW;  // Sprite 旋轉弧動量
  |----- public float Scale;  // Sprite 縮放大小
  |----- public float ScaleW;  // Sprite 縮放動量
  |----- public Vector2 SpriteSpeed;  // Sprite 位移
  |----- public SpriteEffects SpriteEffect;  // Sprite 的 SpriteEffect
  |----- public Rectangle CollisionBox;  // Sprite 的碰撞位置及大小(位置以Location為基準)
  |----- public float layerDepth;  // Sprite 景深 (0為最前,1為最後)
  |----- public Color color;  // Sprite 顏色
  |----- public FrameFormat mFrame;  // Sprite 的 Frame
  |----- public Boolean Remove;   // 是否移除 Sprite
  |----- private double UpdateTime;  // 計算時間
  |
  |=== public SpriteFormat()  // 建構式,設定屬性初始值
  |=== public void Update(GameTime gameTime)  // 更新 Sprite
  |=== public Boolean IsCollision(SpriteFormat SF)  // 檢查是否碰撞
  |=== public void SetByTexture2D(Texture2D Pic)  // 由 Texture2D 建立資料
  |=== public void Set(.......太多自己看= =)  // 設定屬性用函式
  |=== public void SetFrame(.......太多自己看= =)  // 設定Frame用函式
  |=== public void Draw(SpriteBatch DrawPic, Texture2D texture)  // 以 texture 左上點為基準的繪圖
  |=== public void DrawCenter(SpriteBatch DrawPic, Texture2D texture)  // 以 texture 中心點為基準的繪圖


------------------------------------------------------------------ [使用流程]
1. 用Set 和 SetFrame 設定屬性.
2. 用 Update 更新資料.
3. 用 Draw 來畫.


------------------------------------------------------------------ [Class 原始碼]
代碼:

#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
#endregion


namespace catchit
{
    //
    //   Sprite Format ver 0.65 Alpha
    //   
    //   

    public struct FrameFormat
    {
        public int Width;           // Frame 寬度
        public int Height;          // Frame 高度
        public int MaxFrame;        // Frame 最大值
        public int NowFrame;        // 現在的 Frame
        public int MinFrame;        // Frame 最小值
        public int FramePerSecond;  // 每秒顯示幾張 Frame
        public Boolean AutoChange;  // 是否自動更新 Frame
    }

    public class SpriteFormat
    {

        public Vector2 Location;            // Sprite 位置
        public Rectangle sourceRectangle;   // Sprite 取得圖檔內位置及大小
        public Vector2 Center;              // Sprite 中心點
        public float Rotation;              // Sprite 旋轉弧度
        public float RotationW;             // Sprite 旋轉弧動量
        public float Scale;                 // Sprite 縮放大小
        public float ScaleW;                // Sprite 縮放動量
        public Vector2 SpriteSpeed;         // Sprite 位移
        public SpriteEffects SpriteEffect;  // Sprite 的 SpriteEffect
        public Rectangle CollisionBox;      // Sprite 的碰撞位置及大小(位置以Location為基準)
        public float layerDepth;            // Sprite 景深 (0為最前,1為最後)
        public Color color;                 // Sprite 顏色
        public FrameFormat mFrame;          // Sprite 的 Frame
        public Boolean Remove;              // 是否移除 Sprite
        public char CollisionSide;          // N為無碰撞,T為上方,R為右方,B為下方,L為左方

        private double UpdateTime;          // 計算時間


        // 建構式
        public SpriteFormat()
        {
            // 設定初始值
            Location = Vector2.Zero;
            sourceRectangle = Rectangle.Empty;
            Center = Vector2.Zero;
            Rotation = 0.0f;
            RotationW = 0.0f;
            Scale = 1.0f;
            ScaleW = 0.0f;
            SpriteSpeed = Vector2.Zero;
            SpriteEffect = SpriteEffects.None;
            CollisionBox = Rectangle.Empty;
            layerDepth = 0.0f;
            color = Color.White;
            Remove = false;

            mFrame.Width = 0;
            mFrame.Height = 0;
            mFrame.MaxFrame = 0;
            mFrame.MinFrame = 0;
            mFrame.NowFrame = 0;

        }

        // 更新 Sprite 函數
        public void Update(GameTime gameTime)
        {
            // 更新旋轉弧度
            Rotation += RotationW;
            // 更新縮放大小
            Scale += ScaleW;
            // 更新位置
            Location = new Vector2(SpriteSpeed.X + Location.X, SpriteSpeed.Y + Location.Y);

            // 如果自動更新 Frame 為真就計算時間
            if (mFrame.AutoChange)
                UpdateTime += gameTime.ElapsedGameTime.Milliseconds;
            else
                // 否就 歸零
                UpdateTime = 0.0d;
            // 判斷 FramePerSecond 不等於 0 且 時間達到 要換 Frame
            if (mFrame.FramePerSecond != 0 && UpdateTime >= (1000.0 / mFrame.FramePerSecond))
            {
                // Frame + 1
                mFrame.NowFrame++;
                UpdateTime -= 1000.0 / mFrame.FramePerSecond;
                // 如果大於最大 Frame
                if (mFrame.NowFrame > mFrame.MaxFrame)
                    // Frame = 最小 Frame
                    mFrame.NowFrame = mFrame.MinFrame;
            }

        }

        Boolean checkCollision(SpriteFormat A, SpriteFormat B)
        {
            // 檢查 左軸 的 X 是否在 B 碰撞框範圍內
            if (A.Location.X + A.CollisionBox.X >= B.Location.X + B.CollisionBox.X &&
                A.Location.X + A.CollisionBox.X <= B.Location.X + B.CollisionBox.X + B.CollisionBox.Width)
            {
                // 判斷左上角是否在 B 內
                // 檢查 Y 是否在 B 碰撞框範圍內
                if (A.Location.Y + A.CollisionBox.Y >= B.Location.Y + B.CollisionBox.Y &&
                    A.Location.Y + A.CollisionBox.Y <= B.Location.Y + B.CollisionBox.Y + B.CollisionBox.Height)
                    // 有就傳回真
                    return true;
                // 判斷左下角是否在 B 內
                // 檢查 Y 是否在 B 碰撞框範圍內
                if (A.Location.Y + A.CollisionBox.Y + A.CollisionBox.Height >= B.Location.Y + B.CollisionBox.Y &&
                    A.Location.Y + A.CollisionBox.Y + A.CollisionBox.Height <= B.Location.Y + B.CollisionBox.Y + B.CollisionBox.Height)
                    // 有就傳回真
                    return true;
            }

            // 檢查 右軸 的 X 是否在 B 碰撞框範圍內
            if (A.Location.X + A.CollisionBox.X + A.CollisionBox.Width >= B.Location.X + B.CollisionBox.X &&
                A.Location.X + A.CollisionBox.X + A.CollisionBox.Width <= B.Location.X + B.CollisionBox.X + B.CollisionBox.Width)
            {
                // 判斷左上角是否在 B 內
                // 檢查 Y 是否在 B 碰撞框範圍內
                if (A.Location.Y + A.CollisionBox.Y >= B.Location.Y + B.CollisionBox.Y &&
                    A.Location.Y + A.CollisionBox.Y <= B.Location.Y + B.CollisionBox.Y + B.CollisionBox.Height)
                    // 有就傳回真
                    return true;
                // 判斷左下角是否在 B 內
                // 檢查 Y 是否在 B 碰撞框範圍內
                if (A.Location.Y + A.CollisionBox.Y + A.CollisionBox.Height >= B.Location.Y + B.CollisionBox.Y &&
                    A.Location.Y + A.CollisionBox.Y + A.CollisionBox.Height <= B.Location.Y + B.CollisionBox.Y + B.CollisionBox.Height)
                    // 有就傳回真
                    return true;
            }

            // 都沒有就傳回假
            return false;

        }

        // 檢查是否碰撞
        public Boolean IsCollision(SpriteFormat SF)
        {
            // 各自檢查2方頂點是否在對方範圍內
            if (checkCollision(this, SF) || checkCollision(SF, this))
                // 有就傳回真
                return true;
            else
                // 沒有就假
                return false;

        }

        // 由 Texture2D 建立資料
        public void SetByTexture2D(Texture2D Pic)
        {
            // 設定取得圖檔內位置及大小
            sourceRectangle = new Rectangle(0, 0, Pic.Width, Pic.Height);
            // 更新中心位置
            Center = new Vector2(sourceRectangle.Width / 2, sourceRectangle.Height / 2);
        }

        // 使用函數設定資料
        public void Set(Texture2D Pic, Vector2 Location, float Rotation, float RotationW, float Scale, float ScaleW, Vector2 SpriteSpeed, SpriteEffects SpriteEffect, Rectangle CollisionBox)
        {
            this.RotationW = RotationW;
            this.ScaleW = ScaleW;
            this.Set(Pic, Location, Rotation, Scale, SpriteSpeed, SpriteEffect, CollisionBox);
        }
        public void Set(Texture2D Pic, Vector2 Location, float Rotation, float Scale, Vector2 SpriteSpeed, SpriteEffects SpriteEffect, Rectangle CollisionBox)
        {
            this.SpriteSpeed = SpriteSpeed;
            this.SpriteEffect = SpriteEffect;
            this.Set(Pic, Location, Rotation, Scale, CollisionBox);
        }
        public void Set(Texture2D Pic, Vector2 Location, float Rotation, float Scale, Rectangle CollisionBox)
        {
            this.Location = Location;
            this.Rotation = Rotation;
            this.Scale = Scale;
            this.CollisionBox = CollisionBox;
            this.SetByTexture2D(Pic);
        }
        public void SetFrame(int Width, int Height, int MaxFrame, int MinFrame, int NowFrame, Boolean AutoChange)
        {
            this.mFrame.Width = Width;
            this.mFrame.Height = Height;
            this.mFrame.MaxFrame = MaxFrame;
            this.mFrame.MinFrame = MinFrame;
            this.mFrame.NowFrame = NowFrame;
            this.mFrame.AutoChange = AutoChange;
        }

        // 以 texture 左上點為基準的繪圖
        public void Draw(SpriteBatch DrawPic, Texture2D texture)
        {
            DrawPic.Draw(texture, Location, sourceRectangle, color, Rotation, Vector2.Zero, Scale, SpriteEffect, layerDepth);
        }
        // 以 texture 中心點為基準的繪圖
        public void DrawCenter(SpriteBatch DrawPic, Texture2D texture)
        {
            DrawPic.Draw(texture, Location, sourceRectangle, color, Rotation, Center, Scale, SpriteEffect, layerDepth);
        }

    }
}



_________________
已經畢業了!!


babu61509 在 2008-5-24, PM 1:53 星期六 作了第 5 次修改
回頂端
檢視會員個人資料 發送私人訊息
vamper
對這略感興趣的新人


註冊時間: 2007-06-23
文章: 29
來自: 台灣
18.82 果凍幣

發表發表於: 2007-10-28, PM 7:36 星期日    文章主題: Re: [XNA] vol 3 SpriteFormat 介紹... (未完成) 引言回覆

babu61509 寫到:

代碼:
        // 檢查是否碰撞
        public Boolean IsCollision(SpriteFormat SF)
        {
            Rectangle check = SF.CollisionBox;
            // 判斷是否為較小的碰撞框
            if (CollisionBox.Width <= check.Width)
            {
                // 左x軸判斷
                if (CollisionBox.X <= check.X + check.Width && CollisionBox.X >= check.X)
                {
                    // 判斷是否為較小的碰撞框
                    if (CollisionBox.Height <= check.Height)
                    {
                        // 上y軸判斷 (左上角)
                        if (CollisionBox.Y >= check.Y && CollisionBox.Y <= check.Y + check.Height)
                            return true;
                        // 下y軸判斷 (左下角)
                        if (CollisionBox.Y + CollisionBox.Height >= check.Y && CollisionBox.Y + CollisionBox.Height <= check.Y + check.Height)
                            return true;
                    }
                    else if (check.Height < CollisionBox.Height)
                    {
                        // 用較小的來判斷
                        return SF.IsCollision(this);
                    }
            }
            else if (check.Width < CollisionBox.Width)
            {
                // 用較小的來判斷
                return SF.IsCollision(this);
            }
            // 沒碰到
            return false;
        }




我有個問題喔~我先針對一下這兩行:
代碼:
if (CollisionBox.Width <= check.Width)
{
.....

}
else if (check.Width < CollisionBox.Width)
{
.....

}

return false ;



A:CollisionBox.Width 。假設:x = 20 , y = 40 , width = 40 , hegiht = 50
B:check.Width。假設:x = 10 , 20 , width = 100 , height = 10

A <= B 則反之,必 A > B (B < A)

Run 第:
1.
代碼:

if ( A <= B )  //CollisionBox.Width <= check.Width
{
 if(  A <= B ) // CollisionBox.Height <= check.Height
    {
    }
   else if ( B < A ) //check.Height < CollisionBox.Height
   {
      //呼叫SF.IsCollision(this);   <---this就是A,B就是SF吧?
   }
 
}
else if ( B < A )  // check.Width < CollisionBox.Width
{
  //不會呼叫SF.IsCollision(this);
}

Run 第:
2.因為先前呼叫SF.IsCollision(this);所以角色互換

A:CollisionBox.Width 。假設:x = 10 , 20 , width = 100 , height = 10
B:check.Width。假設:x = 20 , y = 40 , width = 40 , hegiht = 50

代碼:
if ( A <= B ) //CollisionBox.Width <= check.Width
{
}
else if ( B < A )  // check.Width < CollisionBox.Width
{
  呼叫SF.IsCollision(this); <---this就是A,B就是SF吧?
}

Run第:

3. 跟Run第1一樣!?

這樣不就永遠跑不到return false !?

我沒測試過,但是我看一下流程,覺得怪怪的。希望給個解答
回頂端
檢視會員個人資料 發送私人訊息 參觀發表人的個人網站
babu61509
散播福音的祭司


註冊時間: 2007-08-26
文章: 142

681.01 果凍幣

發表發表於: 2007-10-29, AM 2:01 星期一    文章主題: 引言回覆

姆...的確會無限迴圈呢@_@

晚一點改好再放上來- -

_________________
已經畢業了!!
回頂端
檢視會員個人資料 發送私人訊息
從之前的文章開始顯示:   
發表新主題   回覆主題    電腦遊戲製作開發設計論壇 首頁 -> 遊戲程式高級班:DirectX、OpenGL及各種圖型函式庫 所有的時間均為 台灣時間 (GMT + 8 小時)
1頁(共1頁)

 
前往:  
無法 在這個版面發表文章
無法 在這個版面回覆文章
無法 在這個版面編輯文章
無法 在這個版面刪除文章
無法 在這個版面進行投票
可以 在這個版面附加檔案
可以 在這個版面下載檔案


Powered by phpBB © 2001, 2005 phpBB Group
正體中文語系由 phpbb-tw 維護製作