zoukankan      html  css  js  c++  java
  • 使用 HitArea 类在 XNA 中测试碰撞,WPXNA(六)

    平方已经开发了一些 Windows Phone 上的一些游戏,算不上什么技术大牛。在这里分享一下经验,仅为了和各位朋友交流经验。平方会逐步将自己编写的类上传到托管项目中,没有什么好名字,就叫 WPXNA 吧,最后请高手绕道而行吧,以免浪费时间。(为了突出重点和减少篇幅,有些示例代码可能不够严谨。)

    碰撞测试

    在游戏中,碰撞测试是很重要的,这可能会影响到游戏的运行效率,当然有些游戏可能不需要碰撞测试。平方编写了一些简单的用于测试碰撞的类 HitArea。

    HitArea 包含三个主要方法:

    protected abstract bool containTesting ( int x, int y );
    
    internal bool ContainTest ( Vector2 location )
    {
        return this.ContainTest ( ( int ) location.X, ( int ) location.Y );
    }
    internal bool ContainTest ( float x, float y )
    { return this.ContainTest ( ( int ) x, ( int ) y ); }
    internal bool ContainTest ( int x, int y )
    {
    
        if ( !this.IsEnabled )
            return false;
    
        return this.containTesting ( x, y );
    }
    
    protected abstract bool hitTesting ( Rectangle rectangle );
    
    internal bool HitTest ( Rectangle rectangle )
    {
    
        if ( !this.IsEnabled )
            return false;
    
        return this.hitTesting ( rectangle );
    }
    
    protected abstract bool hitTesting ( HitArea area );
    
    internal bool HitTest ( HitArea area )
    {
    
        if ( !this.IsEnabled )
            return false;
    
        return this.hitTesting ( area );
    }

    方法 containTesting 用于测试碰撞区是否包含某一个点,你可以指定点的位置,点的 x 坐标和 y 坐标必须是 int 类型的。方法 hitTesting 用于测试碰撞区是否与某一个矩形或者另一个碰撞区发生了碰撞。HitArea 类并没有实现这些方法,而是由其派生类来实现。

    在测试的过程中,我们还判断了 HitArea 类的 IsEnabled 字段,他用来表示碰撞区是否可用。在默认情况下,IsEnabled 为 true。

    internal bool IsEnabled;
    
    protected HitArea ( )
        : this (
        true
        )
    { }
    protected HitArea ( bool isEnabled )
    { this.IsEnabled = isEnabled; }

    所有从 HitArea 派生的类还需要实现 Locate 方法,此方法用来移动碰撞区的位置。

    internal abstract void Locate ( Point position );

    单个矩形的测试

    平方定义了 SingleRectangleHitArea 类,用来完成单一矩形的测试。

    protected readonly Point location;
    protected Rectangle rectangle;
    
    internal Rectangle Rectangle
    {
        get { return this.rectangle; }
    }
    
    internal SingleRectangleHitArea ( Rectangle rectangle )
        : this ( rectangle,
        true
        )
    { }
    internal SingleRectangleHitArea ( Rectangle rectangle, bool isEnabled )
        : base ( isEnabled )
    {
        this.rectangle = rectangle;
        this.location = rectangle.Location;
    }

    字段 location 表示了碰撞区的原始注册位置,属性 Rectangle 表示用来测试的矩形。

    通过实现 containTesting 方法,SingleRectangleHitArea 类就可以测试是否与某一个点发生了碰撞。而实现方法 hitTesting,SingleRectangleHitArea 类可以测试是否与某一个矩形或者某一个碰撞区发生了碰撞。

    protected override bool containTesting ( int x, int y )
    { return this.rectangle.Contains ( x, y ); }
    
    protected override bool hitTesting ( Rectangle rectangle )
    { return this.rectangle.Intersects ( rectangle ); }
    
    protected override bool hitTesting ( HitArea area )
    { return area.HitTest ( this.rectangle ); }
    
    internal override void Locate ( Point location )
    { this.rectangle.Location = new Point ( this.location.X + location.X, this.location.Y + location.Y ); }

    多个矩形的测试

    单一矩形可以用于一些较小的精灵,而对于一些较大的精灵,可能需要使用多个矩形才能更好的进行碰撞测试。

    private readonly List<Point> subLocations = new List<Point> ( );
    private readonly List<Rectangle> subRectangles = new List<Rectangle> ( );
    
    internal MultiRectangleHitArea ( Rectangle rectangle, params Rectangle[] subRectangles )
        : this ( rectangle,
        true,
        subRectangles
        )
    { }
    internal MultiRectangleHitArea ( Rectangle rectangle, bool isEnabled, params Rectangle[] subRectangles )
        : base ( rectangle, isEnabled )
    {
        this.subRectangles.AddRange ( subRectangles );
    
        foreach ( Rectangle subRectangle in subRectangles )
            this.subLocations.Add ( subRectangle.Location );
    
    }

    MultiRectangleHitArea 类继承自 SingleRectangleHitArea 类,除了 SingleRectangleHitArea 中的矩形,还包括一些小矩形,这些小矩形被包含在 SingleRectangleHitArea 的矩形中。

    在测试时,我们首先检测目标是否与 SingleRectangleHitArea 的矩形发生了碰撞,如果发生了碰撞,我们再去检测是否与 MultiRectangleHitArea 中的多个小矩形发生了碰撞。

    protected override bool containTesting ( int x, int y )
    {
    
        if ( !base.containTesting ( x, y ) )
            return false;
    
        foreach ( Rectangle subRectangle in this.subRectangles )
            if ( subRectangle.Contains ( x, y ) )
                return true;
    
        return false;
    }
    
    protected override bool hitTesting ( Rectangle rectangle )
    {
    
        if ( !base.hitTesting ( rectangle ) )
            return false;
    
        foreach ( Rectangle subRectangle in this.subRectangles )
            if ( subRectangle.Intersects ( rectangle ) )
                return true;
    
        return false;
    }
    
    protected override bool hitTesting ( HitArea area )
    {
        
        if ( !base.hitTesting ( area ) )
            return false;
    
        foreach ( Rectangle subRectangle in this.subRectangles )
            if ( area.HitTest ( subRectangle ) )
                return true;
    
        return false;
    }

    一个小例子

    首先,我们定义了两个 SingleRectangleHitArea,并在构造函数中初始化他们。

    private readonly SingleRectangleHitArea hitArea1;
    private readonly SingleRectangleHitArea hitArea2;
    private int step = 1;
    
    public World ( Color backgroundColor )
        : base ( )
    {
        // ...
        
        this.hitArea1 = new SingleRectangleHitArea ( new Rectangle ( 0, 0, 100, 100 ) );
        this.hitArea2 = new SingleRectangleHitArea ( new Rectangle ( 200, 200, 100, 100 ) );
    }

    字段 hitArea1 的位置为 (0, 0),大小为 100。字段 hitArea2 的位置为 (200, 200),大小为 100。所以他们不会发生碰撞。

    private void OnUpdate ( object sender, GameTimerEventArgs e )
    {
    
        this.step++;
    
        if ( this.step == 10 )
            Debug.WriteLine ( "Hit? {0}", this.hitArea1.HitTest ( this.hitArea2 ) );
        else if ( this.step == 20 )
        {
            this.hitArea1.Locate ( new Point ( 150, 150 ) );
            Debug.WriteLine ( "Hit? {0}", this.hitArea1.HitTest ( this.hitArea2 ) );
        }
        else if ( this.step == 30 )
            Debug.WriteLine ( "Hit? {0}", this.hitArea1.ContainTest ( 200, 200 ) );
            
    }

    在上面的代码中,我们移动了 hitArea1 的位置,并重新测试,则 hitArea1 和 hitArea2 发生了碰撞。

    本期视频 http://v.youku.com/v_show/id_XNTY1NzMxODA0.html
    项目地址 http://wp-xna.googlecode.com/

    更多内容 WPXNA
    平方开发的游戏 http://zoyobar.lofter.com/
    QQ 群 213685539

    欢迎访问我在其他位置发布的同一文章:http://www.wpgame.info/post/decc4_65cbf7

  • 相关阅读:
    java io系列23之 BufferedReader(字符缓冲输入流)
    java io系列22之 FileReader和FileWriter
    java io系列21之 InputStreamReader和OutputStreamWriter
    java io系列20之 PipedReader和PipedWriter
    java io系列19之 CharArrayWriter(字符数组输出流)
    java io系列18之 CharArrayReader(字符数组输入流)
    java io系列17之 System.out.println("hello world")原理
    java io系列16之 PrintStream(打印输出流)详解
    java io系列15之 DataOutputStream(数据输出流)的认知、源码和示例
    java io系列14之 DataInputStream(数据输入流)的认知、源码和示例
  • 原文地址:https://www.cnblogs.com/zoyobar/p/wpxna6.html
Copyright © 2011-2022 走看看