虚拟实验室引擎的开发和实现(六、UIPlace)

本文将继承UIObject,实现背景的渲染,包括读取图片。

和VPlace相应,我用一个继承关系来实现虚拟实验室引擎的渲染类,其中,UIPlace对应的是背景,而UIItem对应的是前景,本章将讨论如何实现UIPlace:

image

Xml文件

前文所述,在引擎的设计过程中,我使用两个Xml文件来装载引擎对象的数据:

一个Xml文件(属性文件)包括该对象的特殊属性(例如大小、引擎中的每一个对象都有不同的大小),供VObject使用,VObject对象通过Parse方法从该Xml中获取数据;

另一个Xml文件(配置文件)则表示该对象的显示属性(例如该对象所用的素材,举例说明,一个场景中可能有两棵树,这两棵树所用的图片都是一样的,因此我把这两棵树使用的图片表示在这个Xml文件中),有UIObject使用。UIObject通过LoadConfigFile方法来获取该Xml文件中的数据。

image

属性文件

和Place有关的属性文件如下:

<place name='NBA' width='1800' height='1200' centerX='0' centerY='0'
       x='-800' y='-500' file='engine1/place1/place.xml' />

 

 

配置文件

和Place有关的配置文件如下:

<?xml version="1.0" encoding="utf-8"?>
<place width="100" height="100">
  <mappart left="0" top="0" image="engine1/place1/0-0.jpg" />
  <mappart left="100" top="0" image="engine1/place1/0-1.jpg" />
  <mappart left="200" top="0" image="engine1/place1/0-2.jpg" />
  <mappart left="300" top="0" image="engine1/place1/0-3.jpg" />
  <mappart left="400" top="0" image="engine1/place1/0-4.jpg" />
  <!--…………-->
  <mappart left="500" top="0" image="engine1/place1/0-5.jpg" />
  <mappart left="600" top="0" image="engine1/place1/0-6.jpg" />
</place>

mappart实际上就是构成该场景的图片及该图片所处的位置:

6-8 6-9 6-10

7-8 7-9 7-10

 

关于UIPlace

根据上面的描述,UIPlace主要从事以下工作:

  1. 读取配置文件;
  2. 从配置文件中读取分块图片的地址;
  3. 载入分块图片,并指定位置;
  4. 添加一些UIItem

读取配置文件

该过程UIObject已经完成了,因此只需要重载当配置文件读取完调用的方法OnConfigureFileDownload:

protected override void OnConfigureFileDownload(object sender,
    DownloadStringCompletedEventArgs e)
{
    if (String.IsNullOrEmpty(e.Result)) return;

    XElement data = XElement.Parse(e.Result);

    //…………
}

从配置文件中读取分块图片的地址

在mappart中的图片地址,是以相对路径的形式存在的,例如:

engine1/place1/0-4.jpg

该相对路径,具体是指什么呢?由于Silverlight应用程序编译后,会打包成一个Xap的压缩文件,因此,相对路径实际上是相对于该Xap文件的路径,例如,编译后的Xap为:http://localhost/engine/clientbin/test.xap(该地址可以通过方法Application.Current.Host.Source得到),那么engine1/place1/o-4.jpg,其地址为http://localhost/engine/clientbin/engine1/place1/o-4.jpg。

为了便于调用,我写了一个方法,来将该相对地址转换为绝对地址:

public static Uri GetLocalURI(String path)
{
    if (path.ToLower().StartsWith("http://"))
    {
        return new Uri(path);
    }
    else
    {
        return new Uri(Application.Current.Host.Source, path);
    }
}

载入分块图片,并指定位置

在UIPlace中,添加一个Canvas属性,作为画布:

protected Canvas DrawCanvas { get; set; }

把该画布设置成和UIPlace一样大:

protected override void BindingSource()
{
    base.BindingSource();

    DrawCanvas.SetBinding(WidthProperty, new Binding()
        { Path = new PropertyPath("Width"), Mode = BindingMode.OneWay });
    DrawCanvas.SetBinding(HeightProperty, new Binding()
        { Path = new PropertyPath("Height"), Mode = BindingMode.OneWay });
    //…………
}

修改OnConfigureFileDownload方法,从配置Xml文件中读取每一个地图块的大小、位置,图片。然后将图片绘制在一个同大小的Rectangle上,并按照位置,将该Rectangle添加到画布上:

protected override void OnConfigureFileDownload(object sender, DownloadStringCompletedEventArgs e)
{
    if (String.IsNullOrEmpty(e.Result)) return;

    XElement data = XElement.Parse(e.Result);
    //清空画布
    DrawCanvas.Children.Clear();
    //读取每个地图快的大小
    int width=data.Attribute<int>("width",0,XElementExtensions.Int32Parser);
    int height=data.Attribute<int>("height",0,XElementExtensions.Int32Parser);
    //开始读取地图快
    foreach(var mp in data.Elements("mappart"))
    {
        //新建Rectangle
        Rectangle rect=new Rectangle()
        {
            Width=width,
            Height=height
        };
        //设置该Rectangle的位置
        Canvas.SetLeft(rect, mp.Attribute<int>("left", 0, XElementExtensions.Int32Parser));
        Canvas.SetTop(rect, mp.Attribute<int>("top", 0, XElementExtensions.Int32Parser));
        //准备将图片绘制在Rectangle上
        ImageBrush brush = new ImageBrush();
        brush.AlignmentX = 0;
        brush.AlignmentY = 0;
        //读取图片相对地址
        String image=mp.Attribute("image",String.Empty);
        //贴图
        if(!String.IsNullOrEmpty(image))
        {
            brush.ImageSource = new BitmapImage(URIToolkit.GetLocalURI(image));
            rect.Fill = brush;
        }
        //将Rectangle添加到画布上
        DrawCanvas.Children.Add(rect);

    }
}

添加UIItem

当VPlace的VItem集合修改时,需要在UIPlace上反映出来,例如,当VPlace添加一个VItem时,UIPlace也要添加该VItem的UIItem,类似的,当VPlace删除一个VItem时,UIPlace也要删除相应的UIItem,我们透过覆盖BindingSource方法来实现这个需求:

protected override void BindingSource()
{
    base.BindingSource();

    DrawCanvas.SetBinding(WidthProperty, new Binding()
        { Path = new PropertyPath("Width"), Mode = BindingMode.OneWay });
    DrawCanvas.SetBinding(HeightProperty, new Binding()
        { Path = new PropertyPath("Height"), Mode = BindingMode.OneWay });
    VPlace.Items.CollectionChanged +=
        new NotifyCollectionChangedEventHandler(OnItemsCollectionChanged);
}

OnItemsCollectionChanged方法定义如下:

protected virtual void OnItemsCollectionChanged(object sender,
    NotifyCollectionChangedEventArgs e)
{
    if (e.Action == NotifyCollectionChangedAction.Add)
    {
        foreach (var vi in e.NewItems)
        {
            Children.Add((vi as VItem).UI);
        }
    }
    else if (e.Action == NotifyCollectionChangedAction.Remove)
    {
        foreach (var vi in e.OldItems)
        {
            Children.Remove((vi as VItem).UI);
        }
    }
}

 

继续安室奈美惠的图片:

dsl_u1513p28t3d1643540f326dt20070719035424

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值