3.1 使用SpriteBatch类显示2D图像:加载和绘制图像

问题

你想将一张2D图像绘制到屏幕中以创建一个2D游戏或作为3D游戏的用户界面。你想有一个简单界面可以指定图像显示在屏幕上的位置。

解决方案

XNA Framework已经以SpriteBatch类的形式提供了这个功能,它可以以一个有效率的方式绘制图像。

虽然SpriteBatch的设计以易用性为优先考虑,但它也允许你可以选择一些优化性能的方法,你会在这个教程中看到详细介绍。

注意:因为每个图像是矩形的,所以可以用两个三角形绘制,用一张2D图像作为纹理覆盖其上。SpriteBatch类会自动帮你进行这个操作。因为你实际上绘制的是三角形,使用SpriteBatch类让你可以充分利用硬件加速。

工作原理

在图形编程中,2D图像通常叫做sprite。但是,当一张2D图像用来覆盖在一个表面时,叫做纹理。所以当讨论屏幕上的图像时,我指的是sprite。当讨论绘制sprite要用的颜色时,我指的是纹理。

加载一张纹理

XNA’s Game Studio (GS)支持拖放功能,你可以简单地将纹理拖动到项目中。GS支持很多图像格式。首先,在解决方案浏览器中找到项目的Content文件夹,你可以简单地将一张图像从资源管理器拖动到Content文件夹上。或者也可以通过右击解决方案中的Content文件夹并选择Add→Add Existing Item手动添加,如图3-1所示。

图3-1

图3-1 在XNA项目中添加一个新图像

然后需要在项目中添加一个变量,给新导入的图像起一个名称,这让你可以从项目中访问这个图像。在类变量中添加以下代码:

Texture2D myTexture; 

在代码顶部添加以下代码行:

namespace BookCode 
{
    public class Game1 : Microsoft.Xna.Framework.Game 
    { 
        GraphicsDeviceManager graphics; 
        GraphicsDevice device; 
        SpriteBatch spriteBatch; 
        Texture2D myTexture; 
        
        public Game1() 
        {
            graphics = new GraphicsDeviceManager(this); 
            Content.RootDirectory = "Content"; 
        } 

注意:变量device是为GraphicsDevice创建的快捷方式,因为你将频繁地使用它。因为需要在每次程序重新获得焦点后重新连接GraphicsDevice(例如,在最小化操作之后),所以你需要在LoadContent方法中添加device = graphics.GraphicsDevice; 代码行。

然后,将变量连接到图像,这是在LoadContent方法中进行的。如果图像的文件名是image1. Jpg或image1. Png,那么素材(asset)名称为image1。

myTexture = content.Load<Texture2D>("image1"); 

内容管道(content pipeline)(可参见教程3-9)从磁盘加载图像文件,处理后将它传递到一个变量中。

将图像放置在屏幕上

在XNA中,将图像放置在屏幕上很简单,使用一个SpriteBatch对象可以实现这个功能。 为了对初学者更加容易使用,一个SpriteBatch对象默认已经在创建新XNA项目时创建了,并且已经在LoadContent方法中实例化了。

当心:创建一个新的SpriteBatch对象需要花费大量的时间和资源,所以不要每帧创建一个新的SpriteBatch对象,应该重用在程序开头创建的SpriteBatch对象。

在Draw方法中,你想让SpriteBatch对象绘制纹理:

spriteBatch.Begin(); 
spriteBatch.Draw(myTexture, new Vector2(50, 100), Color.White); 
spriteBatch.End(); 

上面的代码可以在屏幕上绘制图像。第二个参数让你可以指定放置在屏幕上的位置。你可以定义图像的左上角应该被放置到离窗口多少像素的位置。窗口的左上角对应(0,0)点,所以本例中你的图像离开窗口左边缘50个像素,离开窗口上边缘100个像素。在教程的最后你会学到最后一个参数的更多知识。

在屏幕上绘制多个图像

如果你想在屏幕上绘制多个sprite,显然首先需要将纹理导入到项目中并将它们连接到变量。有了对应的名称,一个单独的SpriteBatch对象可以绘制一批sprite。本例中使用两张图像,将它们连接到两个纹理变量。每个纹理被绘制到屏幕的两个不同位置,导致屏幕上绘制了四个sprite:

spriteBatch.Begin(); 
spriteBatch.Draw(myTexture, new Vector2(50, 100), Color.White); 
spriteBatch.Draw(anotherTexture, new Vector2(70, 100), Color.White); 
spriteBatch.Draw(anotherTexture, new Vector2(70, 200), Color.White); 
spriteBatch.Draw(myTexture, new Vector2(100, 200), Color.White); 
spriteBatch.End(); 

将图像绘制到一个矩形中

使用spriteBatch.Draw的另一个重载方法,你可以指定屏幕上的目标矩形,这个矩形表示图像绘制到哪儿。如果目标矩形与图像的大小不同,则图像会自动缩放匹配这个目标矩形。

下面的代码定义了一个拥有与窗口同样大小的目标矩形,起点是左上角的(0,0)。结果是,这个图像会扩展到整个屏幕,这对绘制背景是很有用的:

spriteBatch.Begin(); 
PresentationParameters pp = device.PresentationParameters; 
spriteBatch.Draw(myTexture, new Rectangle(0, 0, pp.BackBufferWidth, pp.BackBufferHeight), Color.White); 
spriteBatch.End(); 

颜色调整

直到现在,你都是用Color. White作为spriteBatch. Draw调用的一个参数。在图像绘制到屏幕之前,它的每个像素的颜色会与这个值相乘。

例如,如果你指定Color. Blue,每个像素的红色和绿色通道会乘以0,蓝色通道会乘以1。这样就会将图像中的红色和绿色分量完全移除。

如果图像只由红色像素构成,所有像素会变成黑色,因为红色通道会乘以0。如果你指定了Color. Purple,红色通道会乘以1,绿色乘以0,蓝色乘以1。所以如果是一张红色图像,它的颜色保持不变。

Color. White参数由红、绿、蓝组成,所以红色,绿色,蓝色通道会乘以1。结果是,你的图像会以初始颜色绘制到屏幕上。

你可以指定一个不为Color. White的值,稍微减弱或增强一个颜色的强度。例如,通过减少红色和绿色通道的颜色强度增加蓝色的强度。

在3D程序中使用SpriteBatch类

无论何时使用SpriteBatch绘制图像,SpriteBatch都会调整显卡的一些设置。如果之后你还要绘制一些3D物体,那么很有可能这些新设置会对3D绘制过程产生无法预料的影响。所以,你想让SpriteBatch保存显卡的初始设置,这样在SpriteBatch完成后可以恢复这些设置:

spriteBatch.Begin(SpriteBlendMode.None, SpriteSortMode.Texture, SaveStateMode.SaveState); 

代码

下面的简单程序在屏幕上绘制了一张图像。注意myTexture变量的定义和初始化,以及如何在Draw方法中绘制这个图像:

using System; using System.Collections.Generic;
using Microsoft.Xna.Framework; 
using Microsoft.Xna.Framework.Audio; 
using Microsoft.Xna.Framework.Content; 
using Microsoft.Xna.Framework.GamerServices; 
using Microsoft.Xna.Framework.Graphics; 
using Microsoft.Xna.Framework.Input; 
using Microsoft.Xna.Framework.Net; 
using Microsoft.Xna.Framework.Storage; 

namespace BookCode 
{
    public class Game1 : Microsoft.Xna.Framework.Game 
    { 
        
        GraphicsDeviceManager graphics; 
        GraphicsDevice device; 
        SpriteBatch spriteBatch; 
        
        Texture2D myTexture; 
        
        public Game1() 
        {
            graphics = new GraphicsDeviceManager(this); 
            Content.RootDirectory = "Content"; 
        }
        
        protected override void Initialize() 
        {
            base.Initialize(); 
        }
        
        protected override void LoadContent() 
        {
            device = graphics.GraphicsDevice; 
            spriteBatch = new SpriteBatch(GraphicsDevice); 
            myTexture = Content.Load<Texture2D>("smile"); 
        } 
        
        protected override void UnloadContent() 
        {
        }
        
        protected override void Update(GameTime gameTime) 
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) 
                this.Exit(); 
            
            base.Update(gameTime); 
        }
        
        protected override void Draw(GameTime gameTime) 
        {
            device.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.CornflowerBlue, 1, 0); 
            spriteBatch.Begin(); 
            spriteBatch.Draw(myTexture, new Vector2(50, 100), Color.White); 
            spriteBatch.End(); 
            base.Draw(gameTime); 
        }
    }
} 

程序截图


发布时间:2009/10/9 下午12:59:52  阅读次数:7081

2006 - 2024,推荐分辨率 1024*768 以上,推荐浏览器 Chrome、Edge 等现代浏览器,截止 2021 年 12 月 5 日的访问次数:1872 万 9823 站长邮箱

沪 ICP 备 18037240 号-1

沪公网安备 31011002002865 号