平方已经开发了一些 Windows Phone 上的一些游戏,算不上什么技术大牛。在这里分享一下经验,仅为了和各位朋友交流经验。平方会逐步将自己编写的类上传到托管项目中,没有什么好名字,就叫 WPXNA 吧,最后请高手绕道而行吧,以免浪费时间。(为了突出重点和减少篇幅,有些示例代码可能不够严谨。)
区域
如果一些单位进入区域,那么他们将被添加特殊的效果,比如:减速或者受到持续的伤害。因此,我们定义了 Region 类来表示区域。
在 Region 中,我们定义了字段 targets 用来表示进入区域的目标。方法 Append 用来为区域增加新的 Spirit,如果该 Spirit 已经包含在区域中,则不能再次被添加。
派生类可以修改 appending 和 appended 方法。方法 appending 可以用来查看 Spirit 的信息,然后根据这些信息来决定是否添加精灵。方法 appended 可以为已经增加的精灵添加各种效果。
internal abstract class Region : Spirit { private readonly List<Spirit> targets = new List<Spirit> ( ); protected Region ( IPlayScene scene, int type, Vector2 location, string movieName, float speed, int angle, HitArea hitArea, int width, int height, double destroySecond ) : base ( scene, type, location, movieName, null, speed, angle, hitArea, width, height, destroySecond, true, false, false, 0 ) { } protected virtual bool appending ( Spirit spirit ) { return true; } protected virtual void appended ( Spirit spirit ) { } internal void Append ( IList<Spirit> spirits ) { if ( null == spirits ) return; foreach ( Spirit spirit in spirits ) this.Append ( spirit ); } internal void Append ( Spirit spirit ) { if ( this.targets.Contains ( spirit ) || !this.appending ( spirit ) ) return; this.targets.Add ( spirit ); this.appended ( spirit ); } protected override void move ( ) { this.Location.X += this.xSpeed; this.Location.Y += this.ySpeed; } protected override Vector2 getMovieLocation ( ) { return this.Location - this.halfSize; } protected override void Dispose ( bool disposing ) { try { if ( disposing ) { this.targets.Clear ( ); } } catch { } base.Dispose ( disposing ); } }其他成员可以参照其他 Spirit 类的解释。
区域管理器
RegionManager 类派生自类 SpiritManager<T>,默认的绘制顺序是 3000。
internal sealed class RegionManager : SpiritManager<Region> { internal event EventHandler<RegionHitAreaEventArgs> HitTesting; internal RegionManager ( ) : base ( 3000 ) { } internal override void Update ( GameTime time ) { if ( null == this.HitTesting ) return; foreach ( Region region in this.Spirits.ToArray ( ) ) { RegionHitAreaEventArgs hitAreaArg = new RegionHitAreaEventArgs ( region ); this.HitTesting ( region, hitAreaArg ); region.Append ( hitAreaArg.Targets ); hitAreaArg.Dispose ( ); } } }事件 HitTesting 可以让外界判断精灵和区域的碰撞,并通过参数 RegionHitAreaEventArgs 返回和区域碰撞的目标。这里你不需要将 RegionHitAreaEventArgs 的 IsHit 属性设置为 true。
示例
场景 SceneT19 是 SceneT18 的扩展,除了有 SceneT18 的功能,还将创建一个区域。
我们定义了类 MyRegion,他是一个区域,可以持续 10 秒的时间。当有精灵进入区域时,他将被销毁。
internal class MyRegion : Region { internal MyRegion ( IPlayScene scene, Vector2 location ) : base ( scene, 1, location, "myr", 0, 0, new SingleRectangleHitArea ( new Rectangle ( -75, -75, 150, 150 ) ), 150, 150, 10 ) { } protected override bool appending ( Spirit spirit ) { spirit.Destroy ( ); return false; } }我们还要定义一个 RegionManager。
private RegionManager regionManager; internal SceneT19 ( ) : base ( Vector2.Zero, GestureType.None, "background1", new Resource[] { new Resource ( "bird2.image", ResourceType.Image, @"image\bird2" ), new Resource ( "bullet.image", ResourceType.Image, @"image\bullet" ), new Resource ( "item.image", ResourceType.Image, @"image\item" ), new Resource ( "pinup.image", ResourceType.Image, @"image\pinup1" ), new Resource ( "r.image", ResourceType.Image, @"image\r1" ), new Resource ( "go.image", ResourceType.Image, @"image\button1" ), }, new Making[] { new Movie ( "bird", "bird2.image", 80, 80, 5, "live", new MovieSequence ( "live", true, new Point ( 1, 1 ), new Point ( 2, 1 ) ) ), new Movie ( "mybutton", "bullet.image", 10, 10, 0, "b", new MovieSequence ( "b", new Point ( 1, 1 ) ) ), new Movie ( "myitem", "item.image", 30, 30, 0, "i", new MovieSequence ( "i", new Point ( 1, 1 ) ) ), new Movie ( "mypinup", "pinup.image", 100, 50, 0, "p", new MovieSequence ( "p", new Point ( 1, 1 ) ) ), new Movie ( "myr", "r.image", 150, 150, 0, "r", new MovieSequence ( "r", new Point ( 1, 1 ) ) ), new Button ( "b.go", "go.image", "GO", new Vector2 ( 10, 690 ), 100, 50, new Point ( 1, 1 ) ), } ) { // ... this.regionManager = new RegionManager ( ); this.regionManager.Scene = this; this.regionManager.HitTesting += this.regionHitTesting; // ... }在方法 regionHitTesting 中,我们将判断哪些子弹进入了区域中,而区域将试图添加这些子弹。
private void regionHitTesting ( object sender, RegionHitAreaEventArgs e ) { List<Spirit> targets = new List<Spirit> ( ); foreach ( Bullet bullet in this.bulletManager.Spirits ) if ( e.HitArea.HitTest ( bullet.HitArea ) ) targets.Add ( bullet ); e.Targets = targets; }最后,我们需要在小鸟被子弹击中后,创建一个区域。
private void bulletHitTesting ( object sender, BulletHitAreaEventArgs e ) { if ( !this.bird.IsDied && e.HitArea.HitTest ( this.bird.HitArea ) ) { e.IsHit = true; e.Targets = new IAssailable[] { this.bird }; if ( !this.is1Hit ) { this.is1Hit = true; this.pinupManager.Append ( new MyHit ( this, new Vector2 ( 0, 400 ) ) ); } this.regionManager.Append ( new MyRegion ( this, new Vector2 ( 100, 100 ) ) ); } }
本期视频 http://v.youku.com/v_show/id_XNTkwMzIyMTYw.html
项目地址 http://wp-xna.googlecode.com/