轉帖|其它|編輯:郝浩|2011-01-30 10:52:23.000|閱讀 914 次
概述:Silverlight游戲開發中時常會碰上一些看似簡單,可做時卻發現挺棘手的問題。于是我打算通過一個小系列將平時較常用以及朋友們提問較多的問題進行歸納,同時分享我自己的解決方案,旨為大家提供更多實用且可行的參考,避免彎路。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
Silverlight游戲開發中時常會碰上一些看似簡單,可做時卻發現挺棘手的問題。于是我打算通過一個小系列將平時較常用以及朋友們提問較多的問題進行歸納,同時分享我自己的解決方案,旨為大家提供更多實用且可行的參考,避免彎路。
一)知己知彼,輕松獲取客戶端相關參考信息
客戶的機器配置各不相同,這我們確實無法控制。然而程序是活的,我們可以像做腳本及插件那樣去適應不同的配置,從而使得每位客戶都能獲得都最佳體驗效果,這也是未來游戲設計所需考慮到的重要環節之一。
首先以獲取客戶端IP地址為例,我們可以通過在在頁面中的Silverlight對象中添加以下參數:
<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="800" height="580">
<param name="initParams" value="<%= String.Format("{0}={1}","ClientIP", Request.UserHostAddress) %>" />
</object>
然后在后臺即可通過Application.Current.Host.InitParams["ClientIP"]讀取客戶端IP地址 同時還可通過HtmlPage.BrowserInformation獲取客戶端瀏覽器的相關信息,比如通過HtmlPage.BrowserInformation.ProductName、HtmlPage.BrowserInformation.ProductVersion分別獲取客戶瀏覽器的類型及版本。
至于如還想獲取客戶端CPU及顯卡等硬件信息則需借助比如Javascript提升瀏覽器權限后再讀取。
或許Silverlight在OOB模式及提升權限后也能做到,本人暫時還未能找到相關的API,望知道的朋友不吝賜教。
以下是該示例的Demo:
< width="600" height="100" data="data:application/x-oleobject;base64,QfXq3+HzJEysrJnDBxUISgAJAAADPgA
AVgoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
type="application/x-silverlight-2">
二)取其精華,實現Javascript的setInterval和setTimeout
只要是用過Javascript的朋友都會對setInterval和setTimeout流連忘返,沒錯,實在是太好用了。游戲中的中毒、冰凍、石化等等這些Buff和DeBuff以及技能的冷卻都需要對過程進行計時。當然已有朋友將setInterval和setTimeout編寫成了C#版本。不過這些代碼還不能整體移植到Silverlight中直接處理UI邏輯,于是我將其進行了如下改造:
readonly int interval = 1000; //間隔時間(毫秒)
/// <summary>
/// 模擬Javascript中的setTimeout在指定時間過后執行指定的方法
/// </summary>
/// <param name="action">方法</param>
/// <param name="interval">間隔(毫秒)</param>
public void setTimeout(Action action, double interval) {
EventHandler handler = null;
DispatcherTimer dispatcherTimer = new DispatcherTimer() { Interval =
TimeSpan.FromMilliseconds(interval) };
dispatcherTimer.Tick += handler = delegate {
dispatcherTimer.Tick -= handler;
dispatcherTimer.Stop();
action();
};
dispatcherTimer.Start();
}
DispatcherTimer timer = new DispatcherTimer();
EventHandler handler = null;
/// <summary>
/// 模擬Javascript中的setInterval在指定時間內重復執行指定的方法
/// </summary>
/// <param name="action">方法</param>
/// <param name="interval">間隔(毫秒)</param>
public void setInterval(Action action, double interval) {
clearInterval();
timer.Interval = TimeSpan.FromMilliseconds(interval);
timer.Tick += handler = delegate { action(); };
timer.Start();
}
/// <summary>
/// 模擬Javascript中的clearInterval停止setInterval
/// </summary>
public void clearInterval() {
timer.Tick -= handler;
timer.Stop();
}
其中的Action可改成帶返回值的Func,適用范圍非常廣;另外,我還為事件做了釋放操作,更有利于封裝處理,比如執行多少次停止,停止時觸發Complete事件等均可輕松拓展;同時還增加了對Javascript中clearInterval函數的模仿,可自由控制setInterval的啟動/停止。
以下是該示例的Demo,每次間隔都會觸發數字+1:
< width="600" height="100" data="data:application/x-oleobject;base64,QfXq3+HzJEysrJnDBxUISgAJAAADPgAAVgoAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAPAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" type="application/x-silverlight-2">
三)借力用力,通過SilverX將Flash動畫轉成Silverlight控件
不可否認,十數年積累下的Flash設計師比Silverlight的多很多且不乏優秀之才;網絡上隨處可見漂亮的Flash動畫,在學習之初或者作為項目中的簡單輔助,我們完全可以通過SilverX這款軟件將沒有復雜AS代碼的Flash動畫(比如Loading、Waiting、login等簡單又漂亮的小動畫)的swf文件直接轉換成Silverlight的xaml控件,老好用了。目前該軟件仍在不斷升級中,對于更復雜的Flash支持也將越來越好,作者深有體會,更期待完美版本的出現~。當前依舊存在的主要缺點有:轉換后的文件容量會變大,顏色有些丟失,性能相對差些,并且好象不購買的話轉出的只有xap而無源碼,當然我們是可以解壓出其中的dll直接使用的。
以下是我隨便找到的一些swf小動畫轉換成xap后的Demo:
< width="600" height="300" data="data:application/x-oleobject;base64,QfXq3+HzJEysrJnDBxUISgAJAAADPgAAAh8AAAAAAAAAAAAAAAAAAAAAAAA
AAAAAPAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" type="application/x-silverlight-2">
< width="600" height="300" data="data:application/x-oleobject;base64,QfXq3+HzJEysrJnDBxUISgAJAAADPgAAAh8AAAAAAAAAAAAA
AAAAAAAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAA=" type="application/x-silverlight-2"> < width="600" height="300" data="data:application/x-oleobject;base64,QfXq3+HzJEysrJnDBxUISgAJAAADPgAAAh8AAAAAAAAAAAAAA
AAAAAAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAA=" type="application/x-silverlight-2"> < width="600" height="300" data="data:application/x-oleobject;base64,QfXq3+HzJEysrJnDBxUISgAJAAADPgAAAh8AAAAAAAAAAAAAAAA
AAAAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAA=" type="application/x-silverlight-2"> < width="600" height="300"
data="data:application/x-oleobject;base64,QfXq3+HzJEysrJnDBxUISgAJAAADPgAAAh8AAAAAAAAAAAAAAAAAAA
AAAAAAAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAA=" type="application/x-silverlight-2"> < width="600" height="100%"
data="data:application/x-oleobject;base64,QfXq3+HzJEysrJnDBxUISgAJAAADPgAAfCQAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAA=" type="application/x-silverlight-2"> < width="600" height="100%"
data="data:application/x-oleobject;base64,QfXq3+HzJEysrJnDBxUISgAJAAADPgAAfCQAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" type="application/x-silverlight-2">
四)綠色體驗,華而實用的九宮格控件
九宮格在Flash中已家喻戶曉,它的好處不言而喻,資源的復用,動態局部搭配,輕松換膚等等。然而對于剛起步的Silverlight來說九宮格著實比較陌生。楊過兄早期就已公布過一些有趣的布局控件,包括九宮格。而游戲中的面板都是通過九宮格實現的,以下是我所編寫的九宮格控件StyleBox,繼承自可拖動的FloatableWindow:
代碼
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace Demo19_3 {
/// <summary>
/// 可浮動窗體
/// </summary>
public abstract class FloatableWindow : Canvas {
/// <summary>
/// 3D整型坐標點
/// </summary>
public struct Point3D {
public int X,
Y,
Z;
public Point3D(int x, int y, int z) {
X = x;
Y = y;
Z = z;
}
}
/// <summary>
/// 獲取或設置中心
/// </summary>
public virtual Point Center { get; set; }
/// <summary>
/// 獲取或設置X、Y坐標
/// </summary>
public virtual Point Coordinate {
get { return new Point(Canvas.GetLeft(this) + Center.X, Canvas.GetTop(this) + Center.Y); }
set { Canvas.SetLeft(this, value.X - Center.X); Canvas.SetTop(this, value.Y - Center.Y); }
}
/// <summary>
/// 獲取或設置Z層次深度
/// </summary>
public int Z {
get { return Canvas.GetZIndex(this); }
set { Canvas.SetZIndex(this, value); }
}
ContentControl HeadContent = new ContentControl(),
BodyContent = new ContentControl(),
FootContent = new ContentControl(),
CloserContent = new ContentControl();
/// <summary>
/// 設置頭部對象
/// </summary>
public object Head {
set { HeadContent.Content = value; }
}
/// <summary>
/// 設置身體對象
/// </summary>
public object Body {
set { BodyContent.Content = value; }
}
/// <summary>
/// 設置腳部對象
/// </summary>
public object Foot {
set { FootContent.Content = value; }
}
/// <summary>
/// 設置關閉按鈕對象
/// </summary>
public object Closer {
set { CloserContent.Content = value; }
}
public double HeadHeight {
get { return HeadContent.Height; }
set { HeadContent.Height = value; }
}
public double BodyHeight {
get { return BodyContent.Height; }
set { BodyContent.Height = value; }
}
public double FootHeight {
get { return FootContent.Height; }
set { FootContent.Height = value; }
}
/// <summary>
/// 設置頭部空間位置
/// </summary>
public Point3D HeadPosition {
set {
Canvas.SetLeft(HeadContent, value.X);
Canvas.SetTop(HeadContent, value.Y);
Canvas.SetZIndex(HeadContent, value.Z);
}
}
/// <summary>
/// 設置身體空間位置
/// </summary>
public Point3D BodyPosition {
set {
Canvas.SetLeft(BodyContent, value.X);
Canvas.SetTop(BodyContent, value.Y);
Canvas.SetZIndex(BodyContent, value.Z);
}
}
/// <summary>
/// 設置腳部空間位置
/// </summary>
public Point3D FootPosition {
set {
Canvas.SetLeft(FootContent, value.X);
Canvas.SetTop(FootContent, value.Y);
Canvas.SetZIndex(FootContent, value.Z);
}
}
/// <summary>
/// 設置關閉按鈕空間位置
/// </summary>
public Point3D CloserPosition {
set {
Canvas.SetLeft(CloserContent, value.X);
Canvas.SetTop(CloserContent, value.Y);
Canvas.SetZIndex(CloserContent, value.Z);
}
}
/// <summary>
/// 動畫飛向
/// </summary>
/// <param name="fromX">起點X</param>
/// <param name="toX">目標X</param>
/// <param name="fromY">起點Y</param>
/// <param name="toY">目標Y</param>
/// <param name="speed">速度倍數</param>
public void AnimationFlyTo(double fromX, double toX, double fromY, double toY, double speed) {
Storyboard storyboard = new Storyboard();
storyboard.Completed += (s, e) => {
Storyboard sb = s as Storyboard;
sb = null;
};
int duration = Convert.ToInt32(Math.Sqrt(Math.Pow((toX - fromX), 2) +
Math.Pow((toY - fromY), 2)) * speed);
DoubleAnimation xAnimation = new DoubleAnimation() {
From = fromX,
To = toX,
Duration = new Duration(TimeSpan.FromMilliseconds(duration))
};
Storyboard.SetTarget(xAnimation, this);
Storyboard.SetTargetProperty(xAnimation, new PropertyPath("(Canvas.Left)"));
storyboard.Children.Add(xAnimation);
DoubleAnimation yAnimation = new DoubleAnimation() {
From = fromY,
To = toY,
Duration = new Duration(TimeSpan.FromMilliseconds(duration))
};
Storyboard.SetTarget(yAnimation, this);
Storyboard.SetTargetProperty(yAnimation, new PropertyPath("(Canvas.Top)"));
storyboard.Children.Add(yAnimation);
storyboard.Begin();
}
/// <summary>
/// 關閉事件
/// </summary>
public event MouseButtonEventHandler Closed;
static int z; //層次
public FloatableWindow() {
this.Children.Add(HeadContent);
this.Children.Add(BodyContent);
this.Children.Add(FootContent);
this.Children.Add(CloserContent);
//設置可拖動方法
bool isMouseCaptured = false; //是否捕獲了鼠標
Point clickPoint = new Point(); //點擊點
HeadContent.MouseLeftButtonDown += (s, e) => {
z++;
Canvas.SetZIndex(this, z);
HeadContent.CaptureMouse();
isMouseCaptured = true;
clickPoint = e.GetPosition(s as UIElement);
e.Handled = true;
};
HeadContent.MouseLeftButtonUp += (s, e) => {
HeadContent.ReleaseMouseCapture();
isMouseCaptured = false;
e.Handled = true;
};
HeadContent.MouseMove += (s, e) => {
if (isMouseCaptured) {
TransformGroup transformGroup = this.RenderTransform as TransformGroup;
if (transformGroup == null) {
transformGroup = new TransformGroup();
}
if (transformGroup != null) {
transformGroup.Children.Add(new TranslateTransform() {
X = e.GetPosition(this).X - clickPoint.X,
Y = e.GetPosition(this).Y - clickPoint.Y
});
this.RenderTransform = transformGroup;
}
}
};
CloserContent.MouseLeftButtonDown += (s, e) => {
if (Closed != null) {
Closed(this, e);
};
e.Handled = true;
};
}
}
}
代碼
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace Demo19_3 {
/// <summary>
/// 九宮格控件
/// </summary>
public sealed class StyleBox : FloatableWindow {
internal TextBlock HeadText = new TextBlock() { HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center };
Image northWestImage = new Image();
Grid northCenterGrid = new Grid();
Image northEastImage = new Image() { Projection = new PlaneProjection() { RotationY = 180 } };
Image centerWestImage = new Image() { Stretch = Stretch.Fill };
ContentControl center = new ContentControl();
Image centerEastImage = new Image() { Stretch = Stretch.Fill, Projection =
new PlaneProjection() { RotationY = 180 } };
Image southWestImage = new Image();
Image southCenterImage = new Image() { Stretch = Stretch.Fill };
Image southEastImage = new Image() { Projection = new PlaneProjection() { RotationY = 180 } };
Grid head = new Grid();
Grid body = new Grid();
Grid foot = new Grid();
public object CenterContent {
set { center.Content = value; }
}
public BitmapImage NorthEdgeImageSource {
set { northWestImage.Source = northEastImage.Source = value; }
}
public BitmapImage NorthImageSource {
set { northCenterGrid.Background = new ImageBrush() { ImageSource = value }; }
}
public double NorthCenterWidth {
set { northCenterGrid.Width = value; }
}
public BitmapImage CenterEdgeImageSource {
set { centerWestImage.Source = centerEastImage.Source = value; }
}
public double CenterWidth {
get { return center.Width; }
set { center.Width = value; }
}
public double CenterEdgeWidth {
set { centerWestImage.Width = centerEastImage.Width = value; }
}
public BitmapImage SouthEdgeImageSource {
set { southWestImage.Source = southEastImage.Source = value; }
}
public BitmapImage SouthImageSource {
set { southCenterImage.Source = value; }
}
public double SouthCenterWidth {
set { southCenterImage.Width = value; }
}
public StyleBox() {
RowDefinition row = new RowDefinition();
head.RowDefinitions.Add(row);
ColumnDefinition[] col = new ColumnDefinition[3];
for (int i = 0; i < 3; i++) {
col[i] = new ColumnDefinition();
head.ColumnDefinitions.Add(col[i]);
}
head.Children.Add(northWestImage); Grid.SetColumn(northWestImage, 0);
northCenterGrid.Children.Add(HeadText);
head.Children.Add(northCenterGrid); Grid.SetColumn(northCenterGrid, 1);
head.Children.Add(northEastImage); Grid.SetColumn(northEastImage, 2);
this.Head = head;
row = new RowDefinition();
body.RowDefinitions.Add(row);
for (int i = 0; i < 3; i++) {
col[i] = new ColumnDefinition();
body.ColumnDefinitions.Add(col[i]);
}
body.Children.Add(centerWestImage); Grid.SetColumn(centerWestImage, 0);
body.Children.Add(center); Grid.SetColumn(center, 1);
body.Children.Add(centerEastImage); Grid.SetColumn(centerEastImage, 2);
this.Body = body;
row = new RowDefinition();
foot.RowDefinitions.Add(row);
for (int i = 0; i < 3; i++) {
col[i] = new ColumnDefinition();
foot.ColumnDefinitions.Add(col[i]);
}
foot.Children.Add(southWestImage); Grid.SetColumn(southWestImage, 0);
foot.Children.Add(southCenterImage); Grid.SetColumn(southCenterImage, 1);
foot.Children.Add(southEastImage); Grid.SetColumn(southEastImage, 2);
this.Foot = foot;
this.Loaded += (s, e) => {
BodyPosition = new Point3D() { Y = (int)HeadHeight };
FootPosition = new Point3D() { Y = (int)HeadHeight + (int)BodyHeight };
};
}
}
}
同樣的素材僅2.2KB可滿足同一款游戲中幾乎所有不同尺寸,不同位置及不同布局的面板需求,實實在在的完美綠色體驗:
以下是該示例Demo,可隨意拖動的九宮格面板:
< width="600" height="100%" data="data:application/x-oleobject;base64,QfXq3+HzJEysrJnDBxUISgAJAAADPgAAfCQAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAA=" type="application/x-silverlight-2">
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自:網絡轉載