Click here to Skip to main content
15,891,033 members
Articles / Mobile Apps / Windows Phone 7

Windows Phone: Are you Game? Part 1

Rate me:
Please Sign up or sign in to vote.
4.77/5 (18 votes)
12 Nov 2011CPOL9 min read 46.2K   693   36  
Introduction to XNA game development for Windows Phone - Includes XNAImage, image manipulation for XNA
using System;
using System.Collections.Generic;
using FarseerPhysics;
using FarseerPhysics.Collision;
using FarseerPhysics.Dynamics;
using Microsoft.Xna.Framework;

public class QuadTreeBroadPhase : IBroadPhase
{
    private const int TreeUpdateThresh = 10000;
    private int _currID;
    private Dictionary<int, Element<FixtureProxy>> _idRegister;
    private List<Element<FixtureProxy>> _moveBuffer;
    private List<Pair> _pairBuffer;
    private QuadTree<FixtureProxy> _quadTree;
    private int _treeMoveNum;

    /// <summary>
    /// Creates a new quad tree broadphase with the specified span.
    /// </summary>
    /// <param name="span">the maximum span of the tree (world size)</param>
    public QuadTreeBroadPhase(AABB span)
    {
        _quadTree = new QuadTree<FixtureProxy>(span, 5, 10);
        _idRegister = new Dictionary<int, Element<FixtureProxy>>();
        _moveBuffer = new List<Element<FixtureProxy>>();
        _pairBuffer = new List<Pair>();
    }

    #region IBroadPhase Members

    ///<summary>
    /// The number of proxies
    ///</summary>
    public int ProxyCount
    {
        get { return _idRegister.Count; }
    }

    public void GetFatAABB(int proxyID, out AABB aabb)
    {
        if (_idRegister.ContainsKey(proxyID))
            aabb = _idRegister[proxyID].Span;
        else
            throw new KeyNotFoundException("proxyID not found in register");
    }

    public void UpdatePairs(BroadphaseDelegate callback)
    {
        _pairBuffer.Clear();
        foreach (Element<FixtureProxy> qtnode in _moveBuffer)
        {
            // Query tree, create pairs and add them pair buffer.
            Query(proxyID => PairBufferQueryCallback(proxyID, qtnode.Value.ProxyId), ref qtnode.Span);
        }
        _moveBuffer.Clear();

        // Sort the pair buffer to expose duplicates.
        _pairBuffer.Sort();

        // Send the pairs back to the client.
        int i = 0;
        while (i < _pairBuffer.Count)
        {
            Pair primaryPair = _pairBuffer[i];
            FixtureProxy userDataA = GetProxy(primaryPair.ProxyIdA);
            FixtureProxy userDataB = GetProxy(primaryPair.ProxyIdB);

            callback(ref userDataA, ref userDataB);
            ++i;

            // Skip any duplicate pairs.
            while (i < _pairBuffer.Count && _pairBuffer[i].ProxyIdA == primaryPair.ProxyIdA &&
                   _pairBuffer[i].ProxyIdB == primaryPair.ProxyIdB)
                ++i;
        }
    }

    /// <summary>
    /// Test overlap of fat AABBs.
    /// </summary>
    /// <param name="proxyIdA">The proxy id A.</param>
    /// <param name="proxyIdB">The proxy id B.</param>
    /// <returns></returns>
    public bool TestOverlap(int proxyIdA, int proxyIdB)
    {
        AABB aabb1;
        AABB aabb2;
        GetFatAABB(proxyIdA, out aabb1);
        GetFatAABB(proxyIdB, out aabb2);
        return AABB.TestOverlap(ref aabb1, ref aabb2);
    }

    public int AddProxy(ref FixtureProxy proxy)
    {
        int proxyID = _currID++;
        proxy.ProxyId = proxyID;
        AABB aabb = Fatten(ref proxy.AABB);
        Element<FixtureProxy> qtnode = new Element<FixtureProxy>(proxy, aabb);

        _idRegister.Add(proxyID, qtnode);
        _quadTree.AddNode(qtnode);

        return proxyID;
    }

    public void RemoveProxy(int proxyId)
    {
        if (_idRegister.ContainsKey(proxyId))
        {
            Element<FixtureProxy> qtnode = _idRegister[proxyId];
            UnbufferMove(qtnode);
            _idRegister.Remove(proxyId);
            _quadTree.RemoveNode(qtnode);
        }
        else
            throw new KeyNotFoundException("proxyID not found in register");
    }

    public void MoveProxy(int proxyId, ref AABB aabb, Vector2 displacement)
    {
        AABB fatAABB;
        GetFatAABB(proxyId, out fatAABB);

        //exit if movement is within fat aabb
        if (fatAABB.Contains(ref aabb))
            return;

        // Extend AABB.
        AABB b = aabb;
        Vector2 r = new Vector2(Settings.AABBExtension, Settings.AABBExtension);
        b.LowerBound = b.LowerBound - r;
        b.UpperBound = b.UpperBound + r;

        // Predict AABB displacement.
        Vector2 d = Settings.AABBMultiplier * displacement;

        if (d.X < 0.0f)
            b.LowerBound.X += d.X;
        else
            b.UpperBound.X += d.X;

        if (d.Y < 0.0f)
            b.LowerBound.Y += d.Y;
        else
            b.UpperBound.Y += d.Y;


        Element<FixtureProxy> qtnode = _idRegister[proxyId];
        qtnode.Value.AABB = b; //not neccesary for QTree, but might be accessed externally
        qtnode.Span = b;

        ReinsertNode(qtnode);

        BufferMove(qtnode);
    }

    public FixtureProxy GetProxy(int proxyId)
    {
        if (_idRegister.ContainsKey(proxyId))
            return _idRegister[proxyId].Value;
        else
            throw new KeyNotFoundException("proxyID not found in register");
    }

    public void TouchProxy(int proxyId)
    {
        if (_idRegister.ContainsKey(proxyId))
            BufferMove(_idRegister[proxyId]);
        else
            throw new KeyNotFoundException("proxyID not found in register");
    }

    public void Query(Func<int, bool> callback, ref AABB query)
    {
        _quadTree.QueryAABB(TransformPredicate(callback), ref query);
    }

    public void RayCast(Func<RayCastInput, int, float> callback, ref RayCastInput input)
    {
        _quadTree.RayCast(TransformRayCallback(callback), ref input);
    }

    #endregion

    private AABB Fatten(ref AABB aabb)
    {
        Vector2 r = new Vector2(Settings.AABBExtension, Settings.AABBExtension);
        return new AABB(aabb.LowerBound - r, aabb.UpperBound + r);
    }

    private Func<Element<FixtureProxy>, bool> TransformPredicate(Func<int, bool> idPredicate)
    {
        Func<Element<FixtureProxy>, bool> qtPred = qtnode => idPredicate(qtnode.Value.ProxyId);
        return qtPred;
    }

    private Func<RayCastInput, Element<FixtureProxy>, float> TransformRayCallback(
        Func<RayCastInput, int, float> callback)
    {
        Func<RayCastInput, Element<FixtureProxy>, float> newCallback =
            (input, qtnode) => callback(input, qtnode.Value.ProxyId);
        return newCallback;
    }

    private bool PairBufferQueryCallback(int proxyID, int baseID)
    {
        // A proxy cannot form a pair with itself.
        if (proxyID == baseID)
            return true;

        Pair p = new Pair();
        p.ProxyIdA = Math.Min(proxyID, baseID);
        p.ProxyIdB = Math.Max(proxyID, baseID);
        _pairBuffer.Add(p);

        return true;
    }

    private void ReconstructTree()
    {
        //this is faster than _quadTree.Reconstruct(), since the quadtree method runs a recusive query to find all nodes.
        _quadTree.Clear();
        foreach (Element<FixtureProxy> elem in _idRegister.Values)
            _quadTree.AddNode(elem);
    }

    private void ReinsertNode(Element<FixtureProxy> qtnode)
    {
        _quadTree.RemoveNode(qtnode);
        _quadTree.AddNode(qtnode);

        if (++_treeMoveNum > TreeUpdateThresh)
        {
            ReconstructTree();
            _treeMoveNum = 0;
        }
    }

    private void BufferMove(Element<FixtureProxy> proxy)
    {
        _moveBuffer.Add(proxy);
    }

    private void UnbufferMove(Element<FixtureProxy> proxy)
    {
        _moveBuffer.Remove(proxy);
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Sea Surveillance AS
Norway Norway
Chief Architect - Sea Surveillance AS.

Specializing in integrated operations and high performance computing solutions.

I’ve been fooling around with computers since the early eighties, I’ve even done work on CP/M and MP/M.

Wrote my first “real” program on a BBC micro model B based on a series in a magazine at that time. It was fun and I got hooked on this thing called programming ...

A few Highlights:

  • High performance application server development
  • Model Driven Architecture and Code generators
  • Real-Time Distributed Solutions
  • C, C++, C#, Java, TSQL, PL/SQL, Delphi, ActionScript, Perl, Rexx
  • Microsoft SQL Server, Oracle RDBMS, IBM DB2, PostGreSQL
  • AMQP, Apache qpid, RabbitMQ, Microsoft Message Queuing, IBM WebSphereMQ, Oracle TuxidoMQ
  • Oracle WebLogic, IBM WebSphere
  • Corba, COM, DCE, WCF
  • AspenTech InfoPlus.21(IP21), OsiSoft PI


More information about what I do for a living can be found at: harlinn.com or LinkedIn

You can contact me at espen@harlinn.no

Comments and Discussions