250 likes | 515 Views
Common Bounding Volumes. Most introductory game programming texts call AABBs simply “bounding boxes”. Circle/Sphere. Axis-Aligned Bounding Box (AABB). Oriented Bounding Box (OBB). Convex Hull. Better bounds, better culling. Faster test, less memory. Circle Bounding Box.
E N D
Common Bounding Volumes • Most introductory game programming texts call AABBs simply “bounding boxes” Circle/Sphere Axis-Aligned Bounding Box(AABB) Oriented Bounding Box (OBB) Convex Hull Better bounds, better culling Faster test, less memory
Circle Bounding Box • Simple storage, easy intersection test • Rotationally invariant Compare Euclidean distance between circle centers against sum of circle radii. boolcircle_intersect(circle a, circle b) { Point d; // d = b.c – a.c d.x = a.c.x – b.c.x; d.y = a.c.y – b.c.y; int dist2 = d.x*d.x + d.y*d.y; // d dot d intradiusSum = a.r + b.r; if (dist2 <= radiusSum * radiusSum) { return true; } else { return false; } } r c struct circle { Point c; // center intr; // radius } struct Point { intx; inty; }
Axis-Aligned Bounding Boxes (AABBs) • Three common representations • Min-max • Min-widths • Center-radius min // min.x<=x<=max.x // min.y<=y<=max.y struct AABB { Point min; Point max; } // min.x<=x<=min.x+dx // min.y<=y<=min.y+dy struct AABB { Point min; intdx; // x width intdy; // y width } // | c.x-x | <= rx | c.y-y | <= ry struct AABB { Point c; intrx; // x radius intry; // y radius } max min dx dy ry rx c Can easily be extended to 3D
Axis Aligned Bounding Box Intersection (min-max) • Two AABBs intersect only if they overlap on both axes a.min.x=b.min.x a.min.x>b.max.x a.max.x<b.min.x a.max.y<b.min.y bool IntersectAABB(AABB a, AABB b) { { if (a.max.x < b.min.x || a.min.x < b.max.x) return false; if (a.max.y < b.min.y || a.min.y < b.max.y) return false; return true; } a.min.y=b.min.y a.min.y>b.max.y
Axis Aligned Bounding Box Intersection (min-width) • Two AABBs intersect only if they overlap on both axes (a.min.x-b.min.x)>b.dx -(a.min.x-b.min.x)>a.dx a.min.x=b.min.x boolIntersectAABB(AABB a, AABB b) { { intt; t=a.min.x-b.min.x; if (t>b.dx || -t>a.dx) return false; t=a.min.y-b.min.y; if (t>b.dy || -t>a.dy) return false; return true; } // Note: requires more operations than // min-max case (2 more subtractions, 2 more negations) -(a.min.y-b.min.y)>a.dy a.min.y=b.min.y (a.min.y-b.min.y)>b.dy
AABB Intersection (center-radius) • Two AABBs intersect only if they overlap on both axes a.c.x-b.c.x >a.rx+b.rx b.c.x-a.c.x >a.rx+b.ry a.c.x=b.c.x b.c.y-a.c.y > a.ry+b.ry bool IntersectAABB(AABB a, AABB b) { { if (Abs(a.c.x – b.c.x) > (a.r.dx + b.r.dx)) return false; if (Abs(a.c.y – b.c.y) > (a.r.dy + b.r.dy)) ) return false; return true; } // Note: Abs() typically single instruction on modern processors a.c.y=b.c.y a.c.y-b.c.y >a.ry+b.ry
Trees root 56 • A tree is a data structure • Places contents into nodes • Each node has • Contents • Pointers to 0 or more other levels • Children are represented as references a b 45 75 d c 24 51 // A simple tree node class Class Node { List<Node> children; // List of references to Nodes int contents; } A tree with 5 nodes (root, a, b, c, d).Root node has contents 56.Node a has contents 45, and two children, c and d.Node b has contents 75, and no children.Node c has contents 24, and no children.Node d has contents 51, and no children.
Tree Operations • Adding a child • Create new node • n = new Node(); • Add it to list of children of parent • parentNode.children.Add(n); • Removing a child • Find and remove child node from list of children • parentNode.children.Remove(childToRemove); • (childToRemove is reference to Node of child to be deleted)
Point Quadtree root 0 1 • A tree where each node has four children • Each level represents subdividing space into 4 quadrants • Each node holds information about one quadrant • A deeper tree indicates more subdivisions MX Quadtree Demo http://donar.umiacs.umd.edu/quadtree/points/mxquad.html Demo both points and rectangles 0 3 1 2 2 3 root 1.1 1.0 0 3 1 2 0 1 1.2 1.3 1.0 1.1 1.2 1.3 2 3
C# Node Representation class Node { Point min[4]; Point max[4]; int level; Node Quad[4]; // holds 4 quadrants List<IGameObject> objectList; // list of game objects in a Node } • quads is an array with four elements • Each element is a reference to a Node • Quad[0] – upper left, etc. • A recursive data structure • Nodes hold pointers to Nodes • Min[] is an array with four elements • Each element is upper left point of quadrant • Max[] holds lower right point of each quadrant • Level indicates how many levels down in the tree • Useful for bounding the depth of the tree Quad[0] Quad[1] Quad[2] Quad[3]
Adding object to tree Insert(Node n, IGameObject g) • Iterate through all 4 quadrants of current node (n) • If at maximum depth of the tree • Add IGameObject to objectList and return • If AABB (bounding box) of IGameObject lies fully within a quadrant • Create child node for that quadrant, if necessary • Then call insert on that node (recursion) • Otherwise, AABB does not lie in just one quadrant • Add to contents list at this level • First call is Insert(root, g) • That is, start at root node for insertions
Finding, removing object in tree Find(Node n, IGameObject g) • Iterate through all 4 quadrants of current node (n) • Check if AABB (bounding box) of IGameObject spans multiple quadrants • Yes: IGameObject is in this node. Return node. • At maximum level of tree? • Yes: IGameObject is at this level • If AABB (bounding box) of IGameObject lies fully within a quadrant • Call find on that node (recursion) • Removing object from tree • Found_node = Find(root, g) • Found_node.objectList.Remove(g)
Publish/Subscribe Example • Consider this: • What if you could automatically find out when your out-of-town friend is in Santa Cruz? • One could imagine your friend having a cell phone that roughly knows its position • You could subscribe to a location service on your friend’s phone • In fact, many people could subscribe to this service • Your friend wouldn’t need to know in advance how many people this would be • When your friend came into Santa Cruz, the phone would publish a message to you • This is an example of a publish/subscribe (pub/sub) service
Publish/Subscribe • In a pub/sub service: • A client subscribes to a service • The service provider stores a list of subscribers • When a particular event occurs, a notification message is published to all subscribers • An event • (in the general sense – C# events are in a few slides) • A noteworthy change in state • “A timely difference that makes a difference” • A notification • A message carrying the information that an event has occurred • In-class acting out of pub/sub information flow
Publish/Subscribe Advantages • Scalable • Can easily add more subscribers • Just add another subscriber to the list in the service provider • Loose coupling • When writing the service provider, do not need to know the complete set of potential future clients • Only need to adhere to a specific interface (data passed with the notification) • Service provider is completely decoupled from the clients • In network-based pub/sub, clients and servers live on separate machines
Publish/Subscribe Disadvantages • Transactional processing • Client may want to treat a series of events as a conceptual whole (a transaction), but doesn’t know how many events it will receive in a row • If events are being used to update a user interface, many events can lead to lots of small, jittery changes to the UI • Complicates information flow • The information a client needs is not always found in the notification message. The client then needs to make further calls to get this information.
Publish/Subscribe Implementations • Pub/Sub is a general information flow pattern • Can be implemented in many ways • Direct connection • Subscribers directly subscribe to information sources • Event message bus • Notifications are sent to a third party, the message bus • Clients subscribe to the message bus • Service providers can come and go, but the clients don’t have to keep re-subscribing • Local/Distributed • Pub/sub can take place inside a local program, or across a network among several distributed programs • In local programs, pub/sub frequently implemented using the Observer design pattern • C# has a special language feature designed specifically for local pub/sub: delegates (and events)
Delegates • A delegate contains a list of references to a method • Must state the return type and parameters of the method • List can contain 0, 1, or many method references • Can think of a delegate as a typed function pointer • Once a delegate is assigned a method, it behaves exactly like that method • That is, you can perform method calls, via the delegate • In the context of pub/sub systems, a delegate holds the list of subscribers • That is, the list of methods to call when an event occurs
// Define delegate type [visibility] delegate [return type] delegate_name ([params]); // Use example class Subject { // Create delegate type "notifier" public delegate void notifier(string message); // Create instance of "notifier" type, called myNotifier public notifiermyNotifier; public void update(string message) { // Check if delegate instance is null // Then call delegate (calls all methods currently // referenced by the delegate) if (myNotifier != null) { // might be calling more than one method! myNotifier(message); } } } Using delegates Define delegate type Specifies return type, parameters and their types Create instance of delegate type Assign method to instance Use = or += operators Use delegate to perform method calls on stored method references Might call more than one method! Defining and Using Delegates
Observer Pattern • The name given to an object-oriented, local implementation of publish-subscribe • Subject • Holds list of subscribed observers in a delegate • Change of state in Subject leads to call on delegate • Acts as a notification to observers of change of state • Observer • Subscribes to subject instances it is interested in • Supplies method to be called upon notification
Problem: Changing AI Behavior • Consider: • AI behavior of an opponent often changes while the game is running • If it gets close to the player, or some other game event occurs • How can this be accomplished in code? • Do not want to destroy opponent object, and create new one with changed AI behavior • I.e., creating a separate subtype of Opponent for each separate opponent behavior isn’t dynamic enough • However, also do not want to encode all possible behaviors inside each type of opponent • Ideally want to re-use AI behaviors across many types of opponent • I.e., putting a big switch/case statement inside each Opponent type won’t work either • “Switch statement” and “duplicate code” bad code smells
Strategy Pattern Client <<interface>> IStrategy IStrategy myStrategy; • Client creates instance of IStrategy subclass • myStrategy = new IStrategySubclass(); • Or, can be given subclass instance in constructor • Inside the client, write code that relates only to IStrategy • myStrategy.Algorithm(); • Will call the Algorithm method on subclass currently assigned to myStrategy + Algorithm() StrategyA StrategyB
Design Principles • Two design principles at play here • Favor composition over inheritance • More flexible to compose IStrategy subclass with Client than to make lots of Client subclasses • Program to Interfaces, not implementations • If you program to an interface, are not tied to a specific class that implements the interface • Can easily create another implementation of the interface, and use that instead • If you program to an interface, substituting a new subclass of that interface is a small change
Homework Read: Chapter 12 (Delegates and Events) from pp. 255-270 in Programming C# 3.0Read: pages 139-148 (Strategy pattern) of C# 3.0 Design PatternsRead: pages 210-217 (Observer Pattern) of C# 3.0 Design Patterns