轉(zhuǎn)帖|其它|編輯:郝浩|2011-01-30 10:52:23.000|閱讀 920 次
概述:Silverlight游戲開發(fā)中時(shí)常會(huì)碰上一些看似簡(jiǎn)單,可做時(shí)卻發(fā)現(xiàn)挺棘手的問(wèn)題。于是我打算通過(guò)一個(gè)小系列將平時(shí)較常用以及朋友們提問(wèn)較多的問(wèn)題進(jìn)行歸納,同時(shí)分享我自己的解決方案,旨為大家提供更多實(shí)用且可行的參考,避免彎路。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
Silverlight游戲開發(fā)中時(shí)常會(huì)碰上一些看似簡(jiǎn)單,可做時(shí)卻發(fā)現(xiàn)挺棘手的問(wèn)題。于是我打算通過(guò)一個(gè)小系列將平時(shí)較常用以及朋友們提問(wèn)較多的問(wèn)題進(jìn)行歸納,同時(shí)分享我自己的解決方案,旨為大家提供更多實(shí)用且可行的參考,避免彎路。
一)知己知彼,輕松獲取客戶端相關(guān)參考信息
客戶的機(jī)器配置各不相同,這我們確實(shí)無(wú)法控制。然而程序是活的,我們可以像做腳本及插件那樣去適應(yīng)不同的配置,從而使得每位客戶都能獲得都最佳體驗(yàn)效果,這也是未來(lái)游戲設(shè)計(jì)所需考慮到的重要環(huán)節(jié)之一。
首先以獲取客戶端IP地址為例,我們可以通過(guò)在在頁(yè)面中的Silverlight對(duì)象中添加以下參數(shù):
<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>
然后在后臺(tái)即可通過(guò)Application.Current.Host.InitParams["ClientIP"]讀取客戶端IP地址 同時(shí)還可通過(guò)HtmlPage.BrowserInformation獲取客戶端瀏覽器的相關(guān)信息,比如通過(guò)HtmlPage.BrowserInformation.ProductName、HtmlPage.BrowserInformation.ProductVersion分別獲取客戶瀏覽器的類型及版本。
至于如還想獲取客戶端CPU及顯卡等硬件信息則需借助比如Javascript提升瀏覽器權(quán)限后再讀取。
或許Silverlight在OOB模式及提升權(quán)限后也能做到,本人暫時(shí)還未能找到相關(guān)的API,望知道的朋友不吝賜教。
以下是該示例的Demo:
< width="600" height="100" data="data:application/x-oleobject;base64,QfXq3+HzJEysrJnDBxUISgAJAAADPgA
AVgoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
type="application/x-silverlight-2">
二)取其精華,實(shí)現(xiàn)Javascript的setInterval和setTimeout
只要是用過(guò)Javascript的朋友都會(huì)對(duì)setInterval和setTimeout流連忘返,沒(méi)錯(cuò),實(shí)在是太好用了。游戲中的中毒、冰凍、石化等等這些Buff和DeBuff以及技能的冷卻都需要對(duì)過(guò)程進(jìn)行計(jì)時(shí)。當(dāng)然已有朋友將setInterval和setTimeout編寫成了C#版本。不過(guò)這些代碼還不能整體移植到Silverlight中直接處理UI邏輯,于是我將其進(jìn)行了如下改造:
readonly int interval = 1000; //間隔時(shí)間(毫秒)
/// <summary>
/// 模擬Javascript中的setTimeout在指定時(shí)間過(guò)后執(zhí)行指定的方法
/// </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在指定時(shí)間內(nèi)重復(fù)執(zhí)行指定的方法
/// </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,適用范圍非常廣;另外,我還為事件做了釋放操作,更有利于封裝處理,比如執(zhí)行多少次停止,停止時(shí)觸發(fā)Complete事件等均可輕松拓展;同時(shí)還增加了對(duì)Javascript中clearInterval函數(shù)的模仿,可自由控制setInterval的啟動(dòng)/停止。
以下是該示例的Demo,每次間隔都會(huì)觸發(fā)數(shù)字+1:
< width="600" height="100" data="data:application/x-oleobject;base64,QfXq3+HzJEysrJnDBxUISgAJAAADPgAAVgoAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAPAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" type="application/x-silverlight-2">
三)借力用力,通過(guò)SilverX將Flash動(dòng)畫轉(zhuǎn)成Silverlight控件
不可否認(rèn),十?dāng)?shù)年積累下的Flash設(shè)計(jì)師比Silverlight的多很多且不乏優(yōu)秀之才;網(wǎng)絡(luò)上隨處可見(jiàn)漂亮的Flash動(dòng)畫,在學(xué)習(xí)之初或者作為項(xiàng)目中的簡(jiǎn)單輔助,我們完全可以通過(guò)SilverX這款軟件將沒(méi)有復(fù)雜AS代碼的Flash動(dòng)畫(比如Loading、Waiting、login等簡(jiǎn)單又漂亮的小動(dòng)畫)的swf文件直接轉(zhuǎn)換成Silverlight的xaml控件,老好用了。目前該軟件仍在不斷升級(jí)中,對(duì)于更復(fù)雜的Flash支持也將越來(lái)越好,作者深有體會(huì),更期待完美版本的出現(xiàn)~。當(dāng)前依舊存在的主要缺點(diǎn)有:轉(zhuǎn)換后的文件容量會(huì)變大,顏色有些丟失,性能相對(duì)差些,并且好象不購(gòu)買的話轉(zhuǎn)出的只有xap而無(wú)源碼,當(dāng)然我們是可以解壓出其中的dll直接使用的。
以下是我隨便找到的一些swf小動(dòng)畫轉(zhuǎn)換成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">
四)綠色體驗(yàn),華而實(shí)用的九宮格控件
九宮格在Flash中已家喻戶曉,它的好處不言而喻,資源的復(fù)用,動(dòng)態(tài)局部搭配,輕松換膚等等。然而對(duì)于剛起步的Silverlight來(lái)說(shuō)九宮格著實(shí)比較陌生。楊過(guò)兄早期就已公布過(guò)一些有趣的布局控件,包括九宮格。而游戲中的面板都是通過(guò)九宮格實(shí)現(xiàn)的,以下是我所編寫的九宮格控件StyleBox,繼承自可拖動(dòng)的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>
/// 可浮動(dòng)窗體
/// </summary>
public abstract class FloatableWindow : Canvas {
/// <summary>
/// 3D整型坐標(biāo)點(diǎn)
/// </summary>
public struct Point3D {
public int X,
Y,
Z;
public Point3D(int x, int y, int z) {
X = x;
Y = y;
Z = z;
}
}
/// <summary>
/// 獲取或設(shè)置中心
/// </summary>
public virtual Point Center { get; set; }
/// <summary>
/// 獲取或設(shè)置X、Y坐標(biāo)
/// </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>
/// 獲取或設(shè)置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>
/// 設(shè)置頭部對(duì)象
/// </summary>
public object Head {
set { HeadContent.Content = value; }
}
/// <summary>
/// 設(shè)置身體對(duì)象
/// </summary>
public object Body {
set { BodyContent.Content = value; }
}
/// <summary>
/// 設(shè)置腳部對(duì)象
/// </summary>
public object Foot {
set { FootContent.Content = value; }
}
/// <summary>
/// 設(shè)置關(guān)閉按鈕對(duì)象
/// </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>
/// 設(shè)置頭部空間位置
/// </summary>
public Point3D HeadPosition {
set {
Canvas.SetLeft(HeadContent, value.X);
Canvas.SetTop(HeadContent, value.Y);
Canvas.SetZIndex(HeadContent, value.Z);
}
}
/// <summary>
/// 設(shè)置身體空間位置
/// </summary>
public Point3D BodyPosition {
set {
Canvas.SetLeft(BodyContent, value.X);
Canvas.SetTop(BodyContent, value.Y);
Canvas.SetZIndex(BodyContent, value.Z);
}
}
/// <summary>
/// 設(shè)置腳部空間位置
/// </summary>
public Point3D FootPosition {
set {
Canvas.SetLeft(FootContent, value.X);
Canvas.SetTop(FootContent, value.Y);
Canvas.SetZIndex(FootContent, value.Z);
}
}
/// <summary>
/// 設(shè)置關(guān)閉按鈕空間位置
/// </summary>
public Point3D CloserPosition {
set {
Canvas.SetLeft(CloserContent, value.X);
Canvas.SetTop(CloserContent, value.Y);
Canvas.SetZIndex(CloserContent, value.Z);
}
}
/// <summary>
/// 動(dòng)畫飛向
/// </summary>
/// <param name="fromX">起點(diǎn)X</param>
/// <param name="toX">目標(biāo)X</param>
/// <param name="fromY">起點(diǎn)Y</param>
/// <param name="toY">目標(biāo)Y</param>
/// <param name="speed">速度倍數(shù)</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>
/// 關(guān)閉事件
/// </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);
//設(shè)置可拖動(dòng)方法
bool isMouseCaptured = false; //是否捕獲了鼠標(biāo)
Point clickPoint = new Point(); //點(diǎn)擊點(diǎn)
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可滿足同一款游戲中幾乎所有不同尺寸,不同位置及不同布局的面板需求,實(shí)實(shí)在在的完美綠色體驗(yàn):
以下是該示例Demo,可隨意拖動(dòng)的九宮格面板:
< width="600" height="100%" data="data:application/x-oleobject;base64,QfXq3+HzJEysrJnDBxUISgAJAAADPgAAfCQAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAA=" type="application/x-silverlight-2">
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請(qǐng)郵件反饋至chenjj@ke049m.cn
文章轉(zhuǎn)載自:網(wǎng)絡(luò)轉(zhuǎn)載