3.场景中的对象-RenderableSceneNode和UISceneNode

SceneNode并没有实现绘制对象的功能,这个功能是由RenderableSceneNode实现的,两者的关系与XNA自带的GameComponent和DrawableGameComponent是类似的。

在实现RenderableSceneNode类之前,先看一下本引擎要实现的对象的层次结构:

节点的层次结构

节点的层次结构

由此图可见,RenderableSceneNode类从SceneNode类继承,而相机无需绘制,所以CameraSceneNode类也从SceneNode类继承,有时在游戏中还要实现一个触发器,比方说玩家移动到一定区域,敌人就会采取行动,这个类TriggerSceneNode也应该从SceneNode类继承。

从RenderableSceneNode类继承的是绘制模型的ModelSceneNode,绘制天空球的SkyDomeSceneNode,绘制地形的TerrainSceneNode和绘制2D控件的UISceneNode,从UISceneNode类还可以派生出按钮类UIButton,文本标签类UILabel和图像类UIImage。

现在看一下RenderableSceneNode类:

namespace StunEngine.SceneNodes
{
    /// <summary>
    /// 场景中的所有可视对象必须从这个类继承。
    /// Draw()必须被绘制的组件重写
    /// </summary>
    public abstract class RenderableSceneNode : SceneNode
    {
        构造函数和成员变量

        /// <summary>
        /// 获取纹理的名称
        /// </summary>
        protected string ColorTextureName
        {
            get { return colorTextureName; }
        }

        /// <summary>
        /// 获取纹理
        /// </summary>
        protected Texture2D ColorTexture
        {
            get { return colorTexture; }
        }

        internal virtual void LoadContent()
        {
            
        }
           
        public override void Initialize()
        {
            if (Engine.GraphicsDevice.IsDisposed)
                return;
            effect= new BasicEffect(engine.GraphicsDevice, null);
            LoadContent();            
            isInitialized = true;
        }
        
        public virtual void Draw(GameTime gameTime)
        {
            
        }
    }
}

因为几乎所有可绘制对象都会包含一张2D纹理,所以有一个叫做colorTexture的Texture2D对象,而BasicEffect对象effect是用来绘制模型的。以后还会碰到更加复杂的情况,比如使用法线映射时,还需要用到另一张法线贴图,BasicEffect也无法满足它的需要,以后会将代码进行重构的,让我们一开始保持简单。

这个引擎的0.1版本并没有实现3D功能,首先实现的是UISceneNode类,这样就可以实现用户菜单和制作简单的2D游戏了。

下面是从RenderableSceneNode继承的UISceneNode类代码:

namespace StunEngine.UI
{
    /// <summary>
    /// 所有UI Scene nodes的抽象基类
    /// </summary>
    public abstract class UISceneNode : RenderableSceneNode
    {
        成员变量和构造函数

        属性

        事件

        重载方法

        /// <summary>
        /// 如果点(x,y)位于控件内部则返回true
        /// </summary>
        /// <param name="x">2D屏幕x坐标</param>
        /// <param name="y">2D屏幕y坐标</param>
        /// <returns></returns>
        public abstract bool IsPointInside(int x, int y);
        
    }
}

控件本质上就是绘制2D图像和文字,所以看一下SpriteBatch.Draw()和SpriteBatch.DrawString()的最复杂的重载方法,这样可以应付最复杂的情况:

public void Draw (Texture2D texture,Vector2 position,Nullable<Rectangle> sourceRectangle, 
        Color color,float rotation,Vector2 origin,Vector2 scale,SpriteEffects effects, float layerDepth) 

public void DrawString (SpriteFont spriteFont,StringBuilder text, Vector2 position,Color color,
        float rotation, Vector2 origin,Vector2 scale,SpriteEffects effects,float layerDepth) 

比较这两个方法,发现相同的参数是position,rotation,origin,scale,effects,layerDepth,因此把这些变量封装在UISceneNode类中,注意看上去相同的还有color,但是这两个color意义是不同的,绘制图像时的color指调制颜色,绘制文本时指文字颜色。

参考一下WinForm程序中的控件,发现还要实现一些鼠标事件。tabindex用于实现按Tab键可以切换控件,诸如文本标签、图像、进度条之类的控件不接受焦点,这可以用TabStop属性控制,具体的实现是在UIManager中进行的,会在下面的教程中讲到。


发布时间:2009/11/20 下午4:33:25  阅读次数:6131

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

沪 ICP 备 18037240 号-1

沪公网安备 31011002002865 号