Silverlight MMORPG网页游戏开发课程[一期] 第九课:HUD与背景音乐
时间:2010-10-19 来源:深蓝色右手
征服玩家的不仅仅是创意,无比动人的视觉体验譬如精美的界面UI同样能让人倾慕,辅以优柔的旋律仿若一缕思绪让您身临其境而流连。深刻的第一印象无限大的冲击着玩家那份内敛的狂热,优秀的游戏作品价值将在欢呼声中被最大化激活。
9.1创建自适应布局之HUD (交叉参考:一切起源于这个真实的世界 制作精美的Mini地图① 制作精美的Mini地图② 制作游戏主菜单面板及鼠标左右键快捷技能栏)
Width = 185,
AcceptsReturn = false,
Foreground = new SolidColorBrush(Colors.White),
Background = new SolidColorBrush(Colors.Transparent)
};
Image image = new Image() { Source = Global.GetProjectImage("HUD/3.png") };
public ChatWindow() {
this.Width = 307;
this.Height = 243;
this.Background = new ImageBrush() { ImageSource = Global.GetProjectImage("HUD/4.png") };
this.Children.Add(textBox); Canvas.SetLeft(textBox, 78); Canvas.SetTop(textBox, 212);
textBox.KeyDown += (s, e) => {
if (e.Key == Key.Enter) {
if (Send != null) { Send(this, new SendEventArgs() { Content = textBox.Text.Trim() }); }
textBox.Text = string.Empty;
e.Handled = true;
}
};
this.Children.Add(image); Canvas.SetLeft(image, 272); Canvas.SetTop(image, 208);
image.MouseLeftButtonDown += (s, e) => {
if (Send != null) { Send(this, new SendEventArgs() { Content = textBox.Text.Trim() }); }
textBox.Text = string.Empty;
e.Handled = true;
};
}
}
然后在MainPage中为该聊天面板实例注册Send事件:
chatWindow.Send += (s, e) => {hero.Say(e.Content);
};
主角将执行说话行为(Say):
/// <summary>/// 说话
/// </summary>
public void Say(string content) {
if (content.Equals("")) { return; }
Dialog dialog = new Dialog(5) {
HostWidth = BodyWidth,
TopOffset = 30
};
this.Children.Add(dialog);
dialog.Completed += new EventHandler(dialog_Completed);
dialog.Show(content);
}
void dialog_Completed(object sender, EventArgs e) {
Dialog dialog = sender as Dialog;
dialog.Completed -= dialog_Completed;
this.Children.Remove(dialog);
}
其中Dialog是本节中我新建的RPG游戏中标准的说话小窗口控件类,通过为其内置一个DispatcherTimer实现该聊天小窗口定时消失:

/// 说话内容框
/// </summary>
public sealed class Dialog : Canvas {
#region 属性
/// <summary>
/// 设置属寄主宽
/// </summary>
public double HostWidth {
set { Canvas.SetLeft(this, (value - width) / 2); }
}
/// <summary>
/// 获取或设置具体头部偏移量
/// </summary>
public int TopOffset { get; set; }
#endregion
#region 构造
const int width = 140;
Rectangle back = new Rectangle() {
Width = width,
Fill = new SolidColorBrush(Colors.Black),
Stroke = new SolidColorBrush(Colors.Gray),
StrokeThickness = 2,
RadiusX = 7,
RadiusY = 7,
Opacity = 0.4
};
TextBlock content = new TextBlock() {
Width = width - 10,
Foreground = new SolidColorBrush(Colors.White),
TextWrapping = TextWrapping.Wrap
};
DispatcherTimer dispatcherTimer = new DispatcherTimer();
/// <param name="duration">持续时间</param>
public Dialog(int duration) {
this.Children.Add(back);
this.Children.Add(content);
Canvas.SetLeft(content, 5); Canvas.SetTop(content, 5);
dispatcherTimer.Interval = TimeSpan.FromSeconds(duration);
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
}
void dispatcherTimer_Tick(object sender, EventArgs e) {
Hide();
if (Completed != null) { Completed(this, new EventArgs()); }
}
#endregion
#region 事件
/// <summary>
/// 说话内容显示后
/// </summary>
public event EventHandler Completed;
#endregion
#region 方法
/// <summary>
/// 显示说话框
/// </summary>
/// <param name="value">内容</param>
public void Show(string value) {
content.Text = value;
back.Height = content.ActualHeight + 10;
Canvas.SetTop(this, -back.Height + TopOffset);//减去精灵名字高度
dispatcherTimer.Start();
}
/// <summary>
/// 隐藏说话框
/// </summary>
public void Hide() {
content.Text = string.Empty;
dispatcherTimer.Stop();
dispatcherTimer.Tick -= dispatcherTimer_Tick;
}
#endregion
}
概括来说,委托和事件是C#中解耦最强有力的工具,通过它我们实现了HUD与其他游戏对象之间的双向交互。
另外,游戏中的HUD各部分布局必须随着Silverlight游戏窗口尺寸的改变而改变,因此我们需要在游戏窗口尺寸改变事件方法中添加对这些部分的自适应布局方案:
/// <summary>/// 游戏窗口尺寸改变
/// </summary>
void Content_Resized(object sender, EventArgs e) {
hero_CoordinateChanged(hero, new DependencyPropertyChangedEventArgs());
if (transition.Visibility == Visibility.Visible) { transition.AdaptToWindowSize(); }
//HUD各部件自适应窗体尺寸
Canvas.SetLeft(targetInfo, Application.Current.Host.Content.ActualWidth / 2 - targetInfo.ActualWidth / 2); Canvas.SetTop(targetInfo, 0);
Canvas.SetLeft(radarMap, Application.Current.Host.Content.ActualWidth - radarMap.ActualWidth); Canvas.SetTop(radarMap, 0);
Canvas.SetLeft(menuBar, Application.Current.Host.Content.ActualWidth - menuBar.ActualWidth); Canvas.SetTop(menuBar, Application.Current.Host.Content.ActualHeight - menuBar.ActualHeight);
Canvas.SetTop(chatWindow, Application.Current.Host.Content.ActualHeight - chatWindow.ActualHeight);
}
以HUD各部分自己的宽、高以及游戏窗体的宽、高为依据进行边缘布局;如此,我们不论是拉伸窗体、最大化窗体、全屏还是OOB模式时,HUD将永远能保持在相对正确的位置上。

if (Application.Current.Host.Content.IsFullScreen) {
Application.Current.Host.Content.IsFullScreen = false;
} else {
Application.Current.Host.Content.IsFullScreen = true;
}
Content_Resized(null, null);
};
9.2场景之背景音乐
游戏的趣味性将伴随着恢弘磅礴的背景音乐无限延伸,Silverlight中自带的MediaElement控件已无法满足我们对游戏音乐的多方面操控,因而需要对其重新进行了封装,取名为MusicPlayer:
/// <summary>/// 媒体播放器控件
/// </summary>
public sealed class MediaPlayer : Canvas {
#region 构造
MediaElement media = new MediaElement() {
IsHitTestVisible = false,
Visibility = Visibility.Collapsed,
AutoPlay = true,
};
public MediaPlayer() {
this.Children.Add(media);
}
#endregion
#region 属性
/// <summary>
/// 获取或设置音量
/// </summary>
public double Volume {
get { return media.Volume; }
set { media.Volume = value; }
}
#endregion
#region 方法
/// <summary>
/// 播放媒体
/// </summary>
/// <param name="uri">路径</param>
/// <param name="loop">是否循环</param>
public void Play(string uri, bool loop) {
media.Source = new Uri(Global.WebPath(string.Format("Media/{0}.mp3", uri)), UriKind.Relative);
media.Position = TimeSpan.Zero;
Start(loop);
}
/// <summary>
/// 媒体开始
/// </summary>
public void Start(bool loop) {
media.MediaEnded -= media_MediaEnded;
if (loop) { media.MediaEnded += media_MediaEnded; }
media.Play();
}
/// <summary>
/// 媒体停止
/// </summary>
public void Stop() {
media.MediaEnded -= media_MediaEnded;
media.Stop();
}
void media_MediaEnded(object sender, RoutedEventArgs e) {
MediaElement media = sender as MediaElement;
media.Position = TimeSpan.Zero;
media.Play();
}
#endregion
}
该播放器是一个简单实现,可以实现循环,同时使用起来也很简单:
music.Play(Media, true);以场景为单位,通过在它们的配置文件中添加参数完全可以实现独立于场景的不同背景音乐,肆意张扬个性的同时大可放心,这些媒体文件都是以数据流的形式逐步获取,无须任何等待及预加载。强大的Silverlight框架为我们铺垫了一切。
本课小结:游戏界面与游戏音乐相辅相成,能否运筹帷幄关系到一款游戏产品的成与败毫不言过。十数年的经验告诉我们倾注设计者灵魂的游戏产品都将成就伟大史诗,选择进步亦或倒退??期待让世界热血沸腾的一刻的降临!
教程Demo在线演示地址:http://silverfuture.cn