1. 程式人生 > >基於C#彈幕類射擊遊戲的實現——(二)渲染

基於C#彈幕類射擊遊戲的實現——(二)渲染

這個遊戲打算是用C#+GDI做~所以渲染效率上還是要進行一些考慮的

這裡對傳統的GDI+封裝了下,通過批處理來提高一些效率

首先給出的是渲染介面的定義,方面以後更換高效能的渲染器(當然很遙遠)

/// <summary>
    /// 渲染器介面
    /// </summary>
    public interface IRenderHandler
    {
    	void Clear(Color backgroundColor);
    	void DrawLine(int x1, int y1, int x2, int y2, Color color);
        void DrawBox(int x, int y, int width, int height, Color color, bool fill);
        void DrawImage(int destX, int destY, int destWidth, int destHeight, Bitmap source, int sourceX, int sourceY, int sourceWidth, int sourceHeight);
        
        object GetSurface();
    }


這是實現一個渲染器需要實現的介面,大體上就這麼多

然後是用GDI實現的一個渲染器

/// <summary>
    /// GDI渲染器
    /// </summary>
    public class GDIRender : IRenderHandler
    {
    	private Bitmap mSurface;
    	private Graphics mG;
    	
    	public GDIRender(int width, int height)
    	{
    		mSurface = new Bitmap(width, height);
    		mG = Graphics.FromImage(mSurface);
    	}
    	
    	public void Clear(Color backgroundColor)
    	{
    		mG.Clear(backgroundColor);
    	}
    	
    	public void DrawLine(int x1, int y1, int x2, int y2, Color color)
        {
            mG.DrawLine(new Pen(color), x1, y1, x2, y2);
        }

        public void DrawBox(int x, int y, int width, int height, Color color, bool fill)
        {
            if (fill == true)
            {
                mG.FillRectangle(new SolidBrush(color), new Rectangle(x - width / 2, y - height / 2, width, height));
            }
            else
            {
                mG.DrawRectangle(new Pen(color), new Rectangle(x - width / 2, y - height / 2, width, height));
            }
        }

        public void DrawImage(int destX, int destY, int destWidth, int destHeight, Bitmap source, int sourceX, int sourceY, int sourceWidth, int sourceHeight)
        {
            mG.DrawImage(source,
                new Rectangle(destX - destWidth / 2, destY - destHeight / 2, destWidth, destHeight),
                new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
                GraphicsUnit.Pixel);
        }
        
        public object GetSurface()
        {
        	return mSurface;
        }
    }


有了這個東西,我們就可以在螢幕上畫東西了。。。

慢著,上面說的批處理呢?別急,馬上來

下面實現的是一個圖形裝置,封裝了一下渲染器

/// <summary>
    /// 圖形裝置
    /// </summary>
    public class GraphicDevice
    {
    	public IRenderHandler RenderHandler;
    	
        private int mRenderStatus; // 渲染器的狀態(0:Normal 1:Begin)
        
        private int mWidth;
        private int mHeight;
        private Color mBackgroundColor;

        public object Surface
        {
            get
            {
            	return RenderHandler.GetSurface();
            }
        }

        private List<RenderObject> mRenderObjects;

        public event RenderOverHandler RenderOver;

        public GraphicDevice(int width, int height, Color backColor)
        {
        	this.RenderHandler = new GDIRender(width, height);
        	
            this.mWidth = width;
            this.mHeight = height;
            this.mBackgroundColor = backColor;

            this.mRenderObjects = new List<RenderObject>();

            this.RenderOver = null;
        }

        public void Begin()
        {
            if (mRenderStatus != 0)
            {
                throw new Exception("上一次呼叫Begin()後未呼叫End()");
            }

            mRenderStatus = 1;
            mRenderObjects.Clear();
            
            RenderHandler.Clear(mBackgroundColor);
        }

        public void End()
        {
            if (mRenderStatus != 1)
            {
                throw new Exception("呼叫End()之前必須呼叫Begin()");
            }

            mRenderStatus = 0;
            mRenderObjects.Sort(DepthComparer);

            int len = mRenderObjects.Count;
            for (int i = 0; i < len; i++)
            {
                mRenderObjects[i].Render(RenderHandler);
            }

            if (RenderOver != null)
            {
                RenderOver(this);
            }
        }

        public void RenderObject(RenderObject obj)
        {
            mRenderObjects.Add(obj);
        }

        private int DepthComparer(RenderObject obj1, RenderObject obj2)
        {
            if (obj1.Depth < obj2.Depth)
            {
                return -1;
            }
            else if (obj1.Depth > obj2.Depth)
            {
                return 1;
            }
            return 0;
        }
    }


在Begin的時候清空需要渲染的東西,在End的時候進行批處理繪製。

繪製的物件是一個叫做RenderObject的類,這個類是基礎渲染圖元,也就是Line,Image之類的基類了

/// <summary>
    /// 渲染目標基類
    /// </summary>
    public class RenderObject
    {
        /// <summary>
        /// 渲染深度(0-100越大越靠前)
        /// </summary>
        public int Depth;

        public RenderObject()
        {
            Depth = 0;
        }

        public virtual void Render(IRenderHandler renderHandler)
        {
        }
    }


然後接下來給出幾種具體實現

public class RenderLine : RenderObject
    {
        public int X1;
        public int Y1;
        public int X2;
        public int Y2;
        public Color Color;

        public RenderLine(int x1, int y1, int x2, int y2, Color color, int depth = 100)
            : base()
        {
            this.Depth = depth;
            this.X1 = x1;
            this.Y1 = y1;
            this.X2 = x2;
            this.Y2 = y2;
            this.Color = color;
        }

		public override void Render(IRenderHandler renderHandler)
        {
        	renderHandler.DrawLine(X1, Y1, X2, Y2, Color);
        }
    }
public class RenderBox : RenderObject
    {
        public int X;
        public int Y;
        public int Width;
        public int Height;
        public Color Color;
        public bool Fill;

        public RenderBox(int x, int y, int width, int height, Color color, bool fill, int depth = 100)
        {
            this.Depth = depth;
            this.X = x;
            this.Y = y;
            this.Width = width;
            this.Height = height;
            this.Color = color;
            this.Fill = fill;
        }

        public override void Render(IRenderHandler renderHandler)
        {
        	renderHandler.DrawBox(X, Y, Width, Height, Color, Fill);
        }
    }


  其餘的類似~~

好了,有了這些東西,我們才真正的開始在螢幕上繪製東西了,大概流程是這樣

GraphiceDevice.Begin()

...

GraphiceDevice.RenderObject(obj);

...

GraphiceDevice.End()