您的位置:首页 > 编程语言 > C#

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十三)制作游戏主菜单面板及鼠标左右键快捷技能栏

2012-03-09 00:00 876 查看
每款MMORPG都有一个主菜单,通常置于窗口的底部。游戏中主角大部分的设置操作都从这里开启。如人物属性、物品(包裹)、技能、任务、队伍、地图、家族、门派、商城、系统设置等等;当然,还包括快捷自定义菜单栏,以及类似《暗黑破坏神》中经典式的左右键快捷技能栏。这些内容在不同的游戏中往往会根据自身的特性稍做调整,但整体上大同小异。本节,我将同样以《剑侠世界》的游戏主界面为例,向家讲解如何在Silverlight中制作一个精美的主菜单面板及鼠标左右键快捷技能栏。
首先,我们需要整出一张主界面的框架素材:





在《剑侠世界》中,该面板从左至右分别是键盘快捷菜单,鼠标左右键快捷菜单及游戏主菜单,那么我首先从右边的主菜单说起。大家可以看到该界面中已经被镂空的部分,这些地方是用来填充相应的菜单按钮的。如果单纯的只是用一张图片来填充,游戏的精致程度将大打折扣;大家回想一下网页中的导航菜单栏,当鼠标进入时它会通过Css或Js变换样式,从而达到突出美化的效果。我们游戏中同样可以采用类似的方案,即当鼠标进入主菜单按钮时,菜单按钮的图片由原先的灰暗切换成明亮,例如:



这是通过两张图片相互切换来实现的按钮突出效果;但在实际开发中,特别是Silverlight这样基于素材时时下载的游戏中,我们需要尽量减少素材资源的数量与容量,因此我特别推荐使用透明高亮遮罩来实现按钮的突出,例如:



当鼠标进入按钮时,我们可以添加一个图标蒙板并使之重叠于按钮图标图片上方,从而同样可以达到高亮突出按钮的效果;不仅如此,通常一款游戏中所有的物品图标和技能图标尺寸是统一的,通过此方式,我们只需一张图标蒙板就能达到所有图标的高亮显示,既大幅节约了素材资源空间,同时也达到了美化效果,一举两得。~嘿嘿
需求都清晰了,该用什么控件来实现呢?当然是QXIcon,不过这次我们得对它进行一些改造,使之目前至少能兼容3种情况:
public enum IconTypes {

/// <summary>

/// 无

/// </summary>

None = 0,

/// <summary>

/// 变换突出

/// </summary>

Transform = 1,

/// <summary>

/// 高亮突出

/// </summary>

Highlights = 2,

}
QXIcon的主要构造如下:

/// <summary>

/// 图标控件

/// </summary>

public QXIcon(IconTypes iconTypes) {

InitializeComponent();

switch (iconTypes) {

case IconTypes.Transform:

this.MouseEnter += delegate { Container.Background = NewSource; };

this.MouseLeave += delegate { Container.Background = _BodySource; };

break;

case IconTypes.Highlights:

Rectangle mask = new Rectangle() { Visibility = Visibility.Collapsed };

Container.Children.Add(mask);

this.MouseEnter += delegate {

mask.Width = this.Width;

mask.Height = this.Height;

mask.Fill = NewSource;

mask.Visibility = Visibility.Visible;

};

this.MouseLeave += delegate { mask.Visibility = Visibility.Collapsed; };

break;

}

}

Brush _BodySource;

/// <summary>

/// 获取或设置图标笔刷

/// </summary>

public Brush BodySource {

get { return _BodySource; }

set { Container.Background = _BodySource = value; }

}

/// <summary>

/// 获取或设置变换后(或蒙板)笔刷

/// </summary>

public Brush NewSource { get; set; }
默认情况下,即参数为IconTypes.None时,该图标控件仅仅是一个带Toolkit的普通图标;当参数为IconTypes.Transform时,图标控件中的图片会根据鼠标进入与离开分别在NewSource和_BodySource之间切换,即前文中提到的第一种情况;而当参数为IconTypes.Highlights时,效果即上叙第二种情况,通过图标蒙板来实现图标的高亮突出。
同时,我也对该QXIcon的Toolkit进行了改造,使之更加新颖别致:

<ToolTipService.ToolTip>

<ToolTip>

<ToolTip.Template>

<ControlTemplate>

<ContentPresenter Content="{TemplateBinding Content}"/>

</ControlTemplate>

</ToolTip.Template>

<ToolTip.Content>

<Canvas x:Name="Dialog">

<Rectangle x:Name="DialogBack" Fill="Black" RadiusX="7" RadiusY="7" Stroke="Gray" StrokeThickness="2" Opacity="0.4" />

<TextBlock x:Name="Details" Foreground="Snow" TextWrapping="Wrap" Width="150" Canvas.Left="5" Canvas.Top="5" />

</Canvas>

</ToolTip.Content>

</ToolTip>

</ToolTipService.ToolTip>

当提示文字发生变化时,它的背景将根据文字的长度与宽度自适应尺寸,且此背景为一个透明度40%的黑色圆角矩形,很漂亮的哦~:
/// <summary>

/// 获取或设置图标悬停提示

/// </summary>

public string Tip {

get { return Details.Text; }

set {

Details.Text = value;

DialogBack.Width = Details.ActualWidth + 10;

DialogBack.Height = Details.ActualHeight + 10;

}

}

最终效果如下:



接下来我们还是利用QXIcon来实现鼠标左右键快捷技能栏,这里我定义左键只负责主角的跑动、对象选中及主角的物理攻击,前面章节中已经全部实现了。而右键则负责施放魔法,此方案应该算是Silverlight的极限了。需求就是当我们在右键快捷按钮图标上点击时,会像《暗黑破坏神》一样,弹出主角已学会(可用)的所有法术和技能。在Silverlight中,我们可以用微软开源工具包中WrapPanel轻松将之实现。WrapPanel是一个可以实现内部控件排列超出限定宽度后自动换行的容器,继承自Panel,和Canvas等容器控件属同一等级,大家可以到http://www.codeplex.com/Silverlight下载最新的版本。本教程示例游戏中,我直接引用它的dll,除它外,该dll还包含其他的一些控件,一方面由于时间有限,我暂时不去单独分离了;另一方面,后期制作中很有可能还会用到其中的某些控件,因此先让它这样吧~,还挺大的呢(112K)。
如果是网络游戏,那么在主角初始化后,我们将从服务器接收到主角的数据,当然包括主角已经掌握的魔法技能,这里我用一个Magic类来表示:

public class Magic {

/// <summary>

/// 代号

/// </summary>

public int Code { get; set; }

/// <summary>

/// 等级

/// </summary>

public int Level { get; set; }

/// <summary>

/// 名称

/// </summary>

public string Name { get; set; }

}

暂时先就这几个参数吧,接下来定义一个主角可用魔法列表List<Magic> availableMagic = new List<Magic>();这里我假设主角已经掌握了代号为0-5的6种魔法,且每种都到了9级,那么我将这6种魔法按如下方式加入到availableMagic表中:

//初始化主角可用的所有魔法

availableMagic.Clear();

for (int i = 0; i < 6; i++) {

availableMagic.Add(new Magic() {

Code = i,

Level = 9,

Name = string.Format("名称:{0}\r\n描述:{1}",

Super.GetXElement(Data.Settings["Arguments"], "Magic",

"Code", i.ToString()).Attribute("Name").Value,

Super.GetXElement(Data.Settings["Arguments"], "Magic", "Code",i.ToString()).Attribute("Description").Value) });

}

当鼠标在右键快捷按钮图标上点击时,我将availableMagic中的所有对象以图标的形式添加进名为rightButtonMagicList的WrapPanel中,由于此Demo中图标的宽高均为27像素,因此我约束rightButtonMagicList宽为270,即一行如果超过10个图标则自动换行。最后为它赋予相应的事件,当点中某个魔法技能,主角当前的右键默认魔法更改为此魔法,且右键快捷按钮图标的魔法也换成它:
……
//右键魔法选择

rightButtonMagicIcon.MouseLeftButtonDown += delegate(object sender, MouseButtonEventArgs e) {

if (rightButtonMagicList == null) {

rightButtonMagicList = new WrapPanel() {

Orientation = Orientation.Horizontal,

Width = 270, //一行放10个图标,每个27宽

};

foreach (Magic magic in availableMagic) {

QXIcon magicIcon = new QXIcon(IconTypes.Highlights) {

BodySource = new ImageBrush() { ImageSource = Super.GetImage(string.Format("/Image/Magic/{0}/0.png", magic.Code)) },

NewSource = new ImageBrush() { ImageSource = Super.GetImage("/Image/Icon/34.png") },

Width = 27,

Height = 27,

Tip = magic.Name,

Tag = magic,

};

magicIcon.MouseLeftButtonDown += delegate(object ss, MouseButtonEventArgs ee) {

QXIcon icon = ss as QXIcon;

Magic m = icon.Tag as Magic;

rightButtonMagicIcon.BodySource = icon.BodySource;

rightButtonMagicIcon.Tip = m.Name;

Leader.CurrentMagic.Code = m.Code;

Leader.CurrentMagic.Level = m.Level;

rightButtonMagicList.Visibility = Visibility.Collapsed;

ee.Handled = true;

};

rightButtonMagicList.Children.Add(magicIcon);

}

BottomMenu.Children.Add(rightButtonMagicList);

Canvas.SetLeft(rightButtonMagicList, 437); Canvas.SetTop(rightButtonMagicList, -Math.Ceiling(rightButtonMagicList.Children.Count / (rightButtonMagicList.Width / 27)) * 27);

} else {

if (rightButtonMagicList.Visibility == Visibility.Collapsed) {

rightButtonMagicList.Visibility = Visibility.Visible;

Canvas.SetTop(rightButtonMagicList, -rightButtonMagicList.ActualHeight);

} else {

rightButtonMagicList.Visibility = Visibility.Collapsed;

}

}

e.Handled = true;

……
具体逻辑大家仔细看就明白了~还算比较简单的。实际效果如下:



另外的,大家不妨自行修改一下循环代码,多加几个魔法上去体验一下WrapPanel的强大:



游戏主界面菜单已初具雏形,接下来的任务就是去完善它的各面板及相应功能~敬请关注。
源码请到目录中下载,在线演示地址:http://silverfuture.cn



作者:
深蓝色右手

出处:
http://alamiye010.cnblogs.com/

教程目录及源码下载:
点击进入(
欢迎加入WPF/Silverlight小组
WPF/Silverlight博客团队)

本文版权归作者和博客园共有,欢迎转载。但未经作者同意必须保留此段声明,且在文章页面显著位置给出原文连接,否则保留追究法律责任的权利。

原文链接:
http://www.cnblogs.com/alamiye010/archive/2009/12/08/1619251.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐