<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-148551349707119893</id><updated>2011-08-01T08:59:11.597-07:00</updated><category term='Random'/><category term='garbage'/><category term='install'/><category term='understand'/><category term='texturing'/><category term='creating'/><category term='3d'/><category term='add'/><category term='device'/><category term='introduce'/><category term='load'/><category term='input'/><category term='benchmark'/><category term='collision'/><category term='first person camera'/><category term='demo'/><category term='sprite'/><category term='input handler'/><category term='c#'/><category term='micro benchmark'/><category term='mouse'/><category term='sound'/><category term='textures'/><category term='managing'/><category term='keyboard'/><category term='Movement'/><category term='update'/><category term='screen'/><category term='xna framework'/><category term='basic'/><category term='camera'/><category term='stationary'/><category term='2d'/><category term='effect'/><category term='reloaded'/><category term='transformation'/><category term='music'/><category term='xna'/><category term='pipeline'/><category term='manage'/><category term='force'/><category term='memory'/><category term='font'/><category term='using skybox'/><category term='loading'/><category term='create'/><category term='c'/><category term='gamepad'/><category term='express'/><category term='xna game'/><category term='split'/><category term='texture'/><category term='creating skybox'/><category term='fps'/><category term='game state'/><category term='framework'/><category term='3d object'/><category term='model'/><category term='content'/><category term='updating'/><category term='use'/><category term='collector'/><title type='text'>XNA Help</title><subtitle type='html'>this website can helped a dummies from making xna games. It have many usefull information that can make you understand how to use xna platform</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>32</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-2496001028021258325</id><published>2008-04-04T21:11:00.001-07:00</published><updated>2008-04-04T21:11:43.538-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='Random'/><category scheme='http://www.blogger.com/atom/ns#' term='Movement'/><title type='text'>Random Movement</title><content type='html'>Besides chasing and evading we can also have our enemies move in random motion. To&lt;br /&gt;do this we need to add some more properties to the enemy class. We want to change&lt;br /&gt;directions every so often (each enemy should have a different timer it uses to determine&lt;br /&gt;when to switch directions). The direction should be random for each enemy (each enemy&lt;br /&gt;will need a random velocity). The properties we need to add to our Enemy class are as&lt;br /&gt;follows:&lt;br /&gt;public float ChangeDirectionTimer;&lt;br /&gt;public Vector3 RandomVelocity;&lt;br /&gt;public int RandomSeconds;&lt;br /&gt;We will create a method called MoveRandomly that will have the logic to move our&lt;br /&gt;enemies in a random motion:&lt;br /&gt;private void MoveRandomly(Enemy enemy, GameTime gameTime)&lt;br /&gt;{&lt;br /&gt;344 CHAPTER 16 AI Algorithms&lt;br /&gt;if (enemy.ChangeDirectionTimer == 0)&lt;br /&gt;enemy.ChangeDirectionTimer =&lt;br /&gt;(float)gameTime.TotalGameTime.TotalMilliseconds;&lt;br /&gt;//has the appropriate amount of time passed?&lt;br /&gt;if (gameTime.TotalGameTime.TotalMilliseconds &gt;&lt;br /&gt;enemy.ChangeDirectionTimer + enemy.RandomSeconds * 1000)&lt;br /&gt;{&lt;br /&gt;enemy.RandomVelocity = Vector3.Zero;&lt;br /&gt;enemy.RandomVelocity.X = rand.Next(-1, 2);&lt;br /&gt;enemy.RandomVelocity.Y = rand.Next(-1, 2);&lt;br /&gt;//restrict to 2D?&lt;br /&gt;if (!restrictToXY)&lt;br /&gt;enemy.RandomVelocity.Z = rand.Next(-1, 2);&lt;br /&gt;enemy.ChangeDirectionTimer = 0;&lt;br /&gt;}&lt;br /&gt;enemy.Velocity = enemy.RandomVelocity;&lt;br /&gt;enemy.Velocity *= moveUnit;&lt;br /&gt;enemy.Color = Color.Orange;&lt;br /&gt;}&lt;br /&gt;Sometimes random movement can appear intelligent. Our method is utilizing the game&lt;br /&gt;time to keep track of how long the enemy should keep moving. It is very similar to the&lt;br /&gt;code we used for our fading method. This method checks to see if enough time has&lt;br /&gt;passed to change directions. Once enough time has elapsed, the enemy velocity vector is&lt;br /&gt;populated by random numbers ranging from -1 to 1. We need to add the following&lt;br /&gt;random number variable to our code:&lt;br /&gt;Random rand = new Random();&lt;br /&gt;Random numbers are very important in AI work. We have taken care to not just have our&lt;br /&gt;enemies be jittery by changing directions every frame. As a result we can have enemies&lt;br /&gt;that look like they are searching or patrolling. None of the code we have seen has been&lt;br /&gt;rocket science. All the algorithms are pretty simple but can provide great results.&lt;br /&gt;We can replace our line in Update with:&lt;br /&gt;MoveRandomly(enemy, gameTime);&lt;br /&gt;Before we can run the code to see the results of our randomly moving enemies, we need&lt;br /&gt;to initialize our properties. We do this inside of the enemy for loop in the Initialize&lt;br /&gt;method:&lt;br /&gt;Random Movement 345&lt;br /&gt;16&lt;br /&gt;enemies[i].ChangeDirectionTimer = 0;&lt;br /&gt;enemies[i].RandomVelocity = Vector3.Left;&lt;br /&gt;enemies[i].RandomSeconds = (i + 2) / 2;&lt;br /&gt;As we run the code we can see that each enemy is just moving around randomly. They&lt;br /&gt;are not moving in synchronization and they definitely appear random.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-2496001028021258325?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/2496001028021258325/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=2496001028021258325' title='2 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/2496001028021258325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/2496001028021258325'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/random-movement.html' title='Random Movement'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-3692006990556975941</id><published>2008-04-04T21:10:00.000-07:00</published><updated>2008-04-04T21:11:15.630-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='collision'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>Collisions</title><content type='html'>This section is going to be pretty detailed. It is something that is best read with a physics&lt;br /&gt;textbook handy to get the full effect. It is not required though, and the actual code is&lt;br /&gt;easier to understand than the math involved. Regardless, it is very beneficial to understand&lt;br /&gt;the reason why this works so we can do further research to determine the best way&lt;br /&gt;to model other important physics needed in our games.&lt;br /&gt;Momentum&lt;br /&gt;When the objects stay in motion, it is because of momentum. Objects in motion have&lt;br /&gt;momentum. Momentum is used to measure our object’s mass and velocity. The formula&lt;br /&gt;to calculate momentum is:&lt;br /&gt;p = mv&lt;br /&gt;p is our object’s momentum and we know that m is our object’s mass and v is the velocity.&lt;br /&gt;The reason we know about mass is because of our force formula. We can substitute&lt;br /&gt;our formula for acceleration in our formula for force:&lt;br /&gt;F = ma = m v / t&lt;br /&gt;Now we can multiply our change in time on both sides, which produces:&lt;br /&gt;Ft = ma = m v&lt;br /&gt;Collisions 295&lt;br /&gt;14&lt;br /&gt;Impulse&lt;br /&gt;Ft is called an impulse. We can do some vector math and multiply our mass by our&lt;br /&gt;change in velocity (the right side of our equation) and see that it can be represented by:&lt;br /&gt;Ft = (mv)&lt;br /&gt;Therefore, we know that our impulse is equal to the change in momentum, which can be&lt;br /&gt;written as follows:&lt;br /&gt;Ft = p&lt;br /&gt;Conservation of Momentum&lt;br /&gt;When objects collide their momentum changes. To be more precise, the magnitude of the&lt;br /&gt;momentum remains the same just in the opposite direction. This is how we can model&lt;br /&gt;our collision response. We can reflect our objects off of each other, knowing that whatever&lt;br /&gt;their momentum was before they collided will remain, but their direction will be&lt;br /&gt;reversed. We just threw two objects into the mix but have only been discussing momentum&lt;br /&gt;on a single object. How does this change our momentum formula? Fortunately, it&lt;br /&gt;does not. This is called the law of conservation of momentum and it means the total&lt;br /&gt;momentum for the objects is constant and does not change. This is true because any&lt;br /&gt;momentum changes are equal in magnitude and opposite in direction. This is expressed&lt;br /&gt;with the following formula:&lt;br /&gt;p1 + p2 = p1 + p2&lt;br /&gt;Kinetic Energy&lt;br /&gt;Now we can discuss Newton’s Third Law of Motion, which basically says that for every&lt;br /&gt;action there is an equal and opposite reaction. Whatever momentum one object&lt;br /&gt;decreases, the other object increases. As momentum is transferred from one object to&lt;br /&gt;another there is another physical property that takes place—kinetic energy. Kinetic energy&lt;br /&gt;is energy associated with moving objects. It is the amount of energy needed to make an&lt;br /&gt;object that is sitting still move. It is also the amount of energy needed to make an object&lt;br /&gt;moving stop and sit still. The formula for kinetic energy is:&lt;br /&gt;Ek = 1⁄2 m v2&lt;br /&gt;When a collision occurs and the amount of kinetic energy is unchanged it is considered&lt;br /&gt;to be an elastic collision. When kinetic energy is lost it is considered to be an inelastic&lt;br /&gt;collision. Objects that collide in the real world will deform and cause a loss of kinetic&lt;br /&gt;energy. If the objects do not deform, no energy is lost.&lt;br /&gt;Coefficient of Restitution&lt;br /&gt;The coefficient of restitution is the measurement of how elastic or inelastic our collision&lt;br /&gt;is based on the types of object that are colliding. The formula for coefficient of restitution&lt;br /&gt;is:&lt;br /&gt;296 CHAPTER 14 Physics Basics&lt;br /&gt;e = (v2f - v1f) / (v1 - v2)&lt;br /&gt;The coefficient of restitution models the velocity before and after a collision takes place&lt;br /&gt;and the loss of kinetic energy happens. The typical value for e is between 0.0 and 1.0&lt;br /&gt;inclusive. A value of 0.0 means the collision is inelastic and 1.0 means the collision is&lt;br /&gt;elastic. The values in between will have a proportionate elastic collision effect. The&lt;br /&gt;subscripts on the preceding formula are specifying which vectors we are using: 1 and 2 are&lt;br /&gt;the two objects and f is the final velocity of that vector after the impact of the collision.&lt;br /&gt;Conservation of Kinetic Energy&lt;br /&gt;We need to discuss the conservation of kinetic energy, which says that the sum of the&lt;br /&gt;kinetic energy of two objects before they collide will be equal to the sum of the kinetic&lt;br /&gt;energy of the two objects after they collide. The formula for the conservation of kinetic&lt;br /&gt;energy is:&lt;br /&gt;Ek1 + Ek2 = Ek1 + Ek2&lt;br /&gt;Broken down into its components, the formula becomes:&lt;br /&gt;1⁄2 m1 v1&lt;br /&gt;2 + 1⁄2 m2 v2&lt;br /&gt;2 = 1⁄2 m1 v1f&lt;br /&gt;2 + 1⁄2 m2 v2f&lt;br /&gt;2&lt;br /&gt;Solving Our Final Velocities&lt;br /&gt;When we are modeling collisions we need to determine our final velocities (which is what&lt;br /&gt;the f in the earlier formula represents). Before we can do that, we need to expand our&lt;br /&gt;conservation of momentum formula from earlier. We will break down the momentum p&lt;br /&gt;into its components as follows:&lt;br /&gt;(m1 v1) + (m2 v2) = (m1 v1f) + (m2 v2f)&lt;br /&gt;Now, we can solve for our final velocity by combining both of our earlier conservation&lt;br /&gt;formulas with our coefficient of restitution formula. Our final velocities will equate to:&lt;br /&gt;v1f = ( (e + 1) m2 v2 + v1(m1 - e m2) ) / (m1 + m2)&lt;br /&gt;v2f = ( (e + 1) m1 v1 - v2(m1 - e m2) ) / (m1 + m2 )&lt;br /&gt;This uses the conservation of kinetic energy formula with our conservation of momentum&lt;br /&gt;formula, along with our coefficient of restitution, which allows us to solve our final velocity&lt;br /&gt;for each object. That is all we need to start modeling realistic collisions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-3692006990556975941?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/3692006990556975941/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=3692006990556975941' title='2 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/3692006990556975941'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/3692006990556975941'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/collisions.html' title='Collisions'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-7549382176038690281</id><published>2008-04-04T21:09:00.002-07:00</published><updated>2008-04-04T21:10:34.796-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='manage'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='game state'/><title type='text'>Managing Game States</title><content type='html'>When we think about our overall game design we should consider the different states our&lt;br /&gt;game will be in. When we made the SimpleGame in Chapter 11, we just used an enumerated&lt;br /&gt;type that we could pick from to change our game state. This was sufficient for that&lt;br /&gt;game, although the method we are going to discuss now would still fit it well without&lt;br /&gt;adding a lot of complexity to the game code.&lt;br /&gt;A common question from those starting out making games is this: “How should I structure&lt;br /&gt;my game code?” This is a valid question with many different answers, each having&lt;br /&gt;its own merit. As with every other aspect of programming, tasks can be in completed&lt;br /&gt;many different ways. For this discussion, we use a structure that is not very hard to implement&lt;br /&gt;and yields some very nice results in terms of flexibility.&lt;br /&gt;Consider the following as a concrete example of the problem we are trying to solve:&lt;br /&gt;1. Game is loaded and the start or title screen is displayed.&lt;br /&gt;2. Player presses A or Start so the start or title screen is removed and the main menu&lt;br /&gt;screen appears.&lt;br /&gt;3. Player selects single player game, the main menu is removed, and a submenu is&lt;br /&gt;displayed.&lt;br /&gt;4. The game is a trial game, so a warning message is also displayed prompting the&lt;br /&gt;gamer to purchase the game or continue with limited play. The message is displayed&lt;br /&gt;on top of our submenu.&lt;br /&gt;Managing Game States 309&lt;br /&gt;15&lt;br /&gt;5. The player accepts the message and the submenu no longer has the message&lt;br /&gt;obstructing the view.&lt;br /&gt;6. The player selects Quick Game from the Single Player menu. The Single Player menu&lt;br /&gt;is removed and we start the level by displaying a start level loading screen.&lt;br /&gt;7. When the level finishes loading, the start level screen is removed and we load up&lt;br /&gt;our game’s scene.&lt;br /&gt;8. The player pauses the game and we bring up a paused screen that overlays our&lt;br /&gt;paused game play, which is a little blurred in the background.&lt;br /&gt;Most of those state changes could be done with a simple enumerated type, but there are a&lt;br /&gt;couple of situations where a simple enumerated type is not sufficient, such as when we&lt;br /&gt;display our message in a modal dialog box that does not allow the gamer to continue&lt;br /&gt;until he or she closes the box. However, we do not want to lose sight of the state we were&lt;br /&gt;just in. We might use this same message dialog box at other times in our game for a tutorial&lt;br /&gt;or hints, and so on. Another example is when the gamer pauses the game. We could&lt;br /&gt;just switch our current state with our paused state and then return to our playing state&lt;br /&gt;when the pause button is toggled by the gamer, but then we could not display our&lt;br /&gt;current game’s scene in a blurred (or grayscaled) manner behind our pause screen.&lt;br /&gt;We are going to create a method that will allow us to handle both of those situations and&lt;br /&gt;give us the flexibility of having access to the different states from within each state. We&lt;br /&gt;are going to create a game state manager class that will control a stack of our different&lt;br /&gt;game states. Instead of just switching between states, we are going to implement a stack.&lt;br /&gt;WHAT IS A STACK?&lt;br /&gt;The typical real-world example computer scientists use to explain a stack is a stack of&lt;br /&gt;plates. We push and pop items on and off of the stack. In our plates example, we&lt;br /&gt;push a plate onto the top of the stack. We can then pop a plate off the top of a stack&lt;br /&gt;(but we need to be careful so we don’t break it). It is a last in, first out (LIFO) method&lt;br /&gt;of processing. We do need to make sure we do not try to pop off a plate if the stack is&lt;br /&gt;empty, but that is easy enough to handle.&lt;br /&gt;We are going to use a stack so we can easily handle situations like adding a pause menu&lt;br /&gt;on top of our currently playing scene state. This way we can continue to draw our scene&lt;br /&gt;even though we are paused. We do not want to update our scene, though, as our enemies&lt;br /&gt;would keep coming for us, our timer would continue to count down, and so on. So when&lt;br /&gt;we pause, we really do want to pause our game play, but we still want to draw our game&lt;br /&gt;scene in its paused state. In fact, we might want to use some of the postprocessing techniques&lt;br /&gt;we learned about to blur out, turn gray, or change our scene some other way when&lt;br /&gt;we are in a paused state. By using a stack we can accomplish any of those things.&lt;br /&gt;Using a stack for game state management is also beneficial when trying to handle things&lt;br /&gt;like dialog boxes, as it effectively pauses the game to give players a hint, tell them the&lt;br /&gt;demo’s time is up, and so on. Another benefit is multiple menus. We can push a menu&lt;br /&gt;310 CHAPTER 15 Finite State Machines and Game State Management&lt;br /&gt;state on top of our game play if the user backs out (or pauses) and then offer an options&lt;br /&gt;menu and sound options or controller options under that. With a stack we have the flexibility&lt;br /&gt;to leave our previous menus displayed, or have our screen replace them. With a&lt;br /&gt;simple switch statement on an enumerated type this would not be possible.&lt;br /&gt;Fortunately, with all of this flexibility we do not increase the complexity of our code very&lt;br /&gt;much. The principle is an easy one to grasp. We are going to have a game state manager&lt;br /&gt;that will manage the different states in our game. It will be implementing a stack to hold&lt;br /&gt;our states. Each state will contain logic that determines what happens next. The states&lt;br /&gt;themselves will drive the game flow.&lt;br /&gt;Each state will inherit from a base game state abstract class. This abstract class will inherit&lt;br /&gt;from the DrawableGameComponent class. Each game state that inherits from our abstract&lt;br /&gt;state will be a game service. There are two reasons for this. One is that we want our state&lt;br /&gt;objects to be singleton objects because we do not want more than one instance of our&lt;br /&gt;state created. The second reason we are making it into a game service is because our game&lt;br /&gt;state manager will need access to the states.&lt;br /&gt;Our game state manager also inherits from GameComponent because it is a game service&lt;br /&gt;that our states need a reference to. The game state manager will include an&lt;br /&gt;OnStateChange event. Normally, other objects would register for an event like this.&lt;br /&gt;Instead, we are going to expose the event handler in our game states and have our game&lt;br /&gt;manager manage the event registration process for our game states. The exposed event&lt;br /&gt;handler in our game states will be called StateChanged.&lt;br /&gt;This StateChanged method in our game state class can be overridden but by default it will&lt;br /&gt;simply check to see if the current state of the game is itself. If it is, it will set its Enable&lt;br /&gt;and Visible properties to true; otherwise it will set them to false. So by default, when a&lt;br /&gt;state is loaded, but not at the top of the stack, it will not update itself nor will it draw&lt;br /&gt;itself. All active game states will have this event handler executed whenever our game&lt;br /&gt;changes state. Each state could also search the stack to see if it contains some other state&lt;br /&gt;and if so do some different processing. Because our StateChanged event handler will be&lt;br /&gt;protected, the actual game states can implement any functionality they want to as the&lt;br /&gt;game state changes. We can see that this system is pretty flexible.&lt;br /&gt;Because we want our objects to use the singleton pattern and we want our states to be&lt;br /&gt;game services so each state can access other states if needed, we can combine those&lt;br /&gt;two requirements because the game service collection can only have one object in its&lt;br /&gt;collection with a particular interface. Therefore each one of our states will need its&lt;br /&gt;own interface, but we saw earlier that this can be a blank interface. In our situation, we&lt;br /&gt;are going to have an IGameState interface, but then each one of our states will have its&lt;br /&gt;own interface that implements the IGameState interface.&lt;br /&gt;We need to be able to make comparisons between our game states. Mainly, we need to&lt;br /&gt;make comparisons between our game manager’s current state and a particular game state.&lt;br /&gt;Enumerated types obviously lend themselves to comparisons easily, but what about actual&lt;br /&gt;game state objects? Fortunately, we can just as easily compare our object references and&lt;br /&gt;this is why it is important that there is only one instance of the object—so our reference&lt;br /&gt;is always the same. We will create a property called Value, which is of type GameState.&lt;br /&gt;This property allows us to perform the comparisons that we need.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-7549382176038690281?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/7549382176038690281/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=7549382176038690281' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/7549382176038690281'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/7549382176038690281'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/managing-game-states.html' title='Managing Game States'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-1632659931227406862</id><published>2008-04-04T21:09:00.001-07:00</published><updated>2008-04-04T21:09:33.087-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='force'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>Force</title><content type='html'>Force changes the acceleration of an object. For example, when we hit a baseball the&lt;br /&gt;acceleration of the ball is changed because we applied force (in the form of swinging a&lt;br /&gt;bat) to the ball. If the ball was pitched to us, then it had a positive acceleration coming&lt;br /&gt;toward us; when we hit it we changed the acceleration to the negative direction.&lt;br /&gt;Force is a very important concept in physics. This is understandable because it is&lt;br /&gt;constantly in effect. For example, even when we are sitting down there is a force of&lt;br /&gt;gravity keeping us in the chair. The first example with the baseball is considered contact&lt;br /&gt;force, as an object (the bat) made contact with the ball to make it change its acceleration.&lt;br /&gt;Gravity is considered a field force (or a force-at-a-distance) because it does not have to&lt;br /&gt;have contact with the object while applying force. Gravity causes items to be drawn to&lt;br /&gt;the Earth’s core. This is why we can sit (and stand) and not float about. This is why we&lt;br /&gt;have weight. It is all because of gravity. If there were an object on the floor it would be&lt;br /&gt;sitting on the floor because of gravity. If we tried to pick it up, we would have to apply&lt;br /&gt;enough force to counteract the force that gravity is applying to it. In outer space, objects&lt;br /&gt;float around and are very light because regardless of their mass (assuming it is not as large&lt;br /&gt;as a planet) they do not weigh much at all because there is no force pushing them down.&lt;br /&gt;Mass is the amount of physical matter an object comprises. With the force of gravity our&lt;br /&gt;mass has weight. The more mass an object has, the more it weighs on Earth. The larger&lt;br /&gt;the mass, the more force is applied against that object to bring it toward the Earth’s core.&lt;br /&gt;When we try to move an object, we have to apply enough force to accelerate the object.&lt;br /&gt;CHAPTER 294 14 Physics Basics&lt;br /&gt;If we do not apply as much force to lift the object upward as gravity is applying to the&lt;br /&gt;object downward, the object will not move.&lt;br /&gt;Newton’s Second Law of Motion describes the relationship between an object’s mass and&lt;br /&gt;acceleration with the force applied to the object. The formula is:&lt;br /&gt;F = ma&lt;br /&gt;We know that acceleration is a vector, and force is a vector as well. This makes sense as we&lt;br /&gt;think about the fact that when we hit that baseball it can go in multiple directions (pop&lt;br /&gt;fly, foul ball, etc.). This is because we are creating acceleration when we apply force to the&lt;br /&gt;object at different angles. Our mass is a scalar value (one dimension) and not a vector&lt;br /&gt;(multiple dimensions). We could also write the preceding formula as:&lt;br /&gt;a = F/m&lt;br /&gt;In our previous code example we had an invisible force acting on our sphere that was&lt;br /&gt;generating the acceleration of the sphere. Newton’s First Law of Motion basically states&lt;br /&gt;that objects that are in motion stay in motion and objects that are sitting still stay still.&lt;br /&gt;Our previous demo shows this as well, as if we do not press any keys to accelerate our&lt;br /&gt;sphere it stays at rest. Once we do apply some force to the object, it accelerates and stays&lt;br /&gt;in motion.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-1632659931227406862?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/1632659931227406862/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=1632659931227406862' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/1632659931227406862'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/1632659931227406862'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/force.html' title='Force'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-6038479966017682697</id><published>2008-04-04T21:08:00.002-07:00</published><updated>2008-04-04T21:09:11.885-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sound'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='add'/><title type='text'>Adding Sounds</title><content type='html'>We can add in some sounds to help the game out some. We already have our sound&lt;br /&gt;manager class from Chapter 7, “Sounds and Music,” so we do not need to write any new&lt;br /&gt;code for that. Instead of going through the hassle of creating another XACT project, we&lt;br /&gt;will simply copy the XACT project and sound files from our Chapter 7 Sound Demo&lt;br /&gt;project folder. We should create a Sounds subfolder in our Content folder in our project&lt;br /&gt;to store the files. We only need to have the XACT project included in the project with the&lt;br /&gt;wave files just in the same directory, but not in the solution itself.&lt;br /&gt;We need to declare our sound manager variable and we need to initialize it in our&lt;br /&gt;constructor like all of our other game components:&lt;br /&gt;sound = new SoundManager(this, “Chapter7”);&lt;br /&gt;Components.Add(sound);&lt;br /&gt;Now, we can create our playlist just like we did in the SoundDemo project by adding the&lt;br /&gt;following code to our Initialize method:&lt;br /&gt;string[] playList = { “Song1”, “Song2”, “Song3” };&lt;br /&gt;sound.StartPlayList(playList);&lt;br /&gt;Finally, we should play the explosion sound we set up back in Chapter 7. We should do&lt;br /&gt;this right after we start our explosion when our enemy dies, so we need to add the following&lt;br /&gt;statement at the end of the player.Attacking condition inside of the&lt;br /&gt;CheckForCollisions method:&lt;br /&gt;sound.Play(“explosion”);&lt;br /&gt;Now, we have our songs playing and when we kick a robot we not only see an explosion&lt;br /&gt;but we hear one, too.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-6038479966017682697?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/6038479966017682697/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=6038479966017682697' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/6038479966017682697'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/6038479966017682697'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/adding-sounds.html' title='Adding Sounds'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-2185782840642852010</id><published>2008-04-04T21:08:00.001-07:00</published><updated>2008-04-04T21:08:48.490-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='use'/><category scheme='http://www.blogger.com/atom/ns#' term='font'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='sprite'/><title type='text'>Using Sprite Fonts</title><content type='html'>The XNA Framework 1.0 Refresh includes built-in font support. We can use any TrueType&lt;br /&gt;font in our games. It also allows use of bitmaps, which can either be drawn by hand or be&lt;br /&gt;generated with the Bitmap Font Make Utility (ttf2bmp). This utility can be found on XNA&lt;br /&gt;Creators Club Online at&lt;br /&gt;http://creators.xna.com/Headlines/utilities/archive/2007/04/26/Bitmap-Font-Maker-&lt;br /&gt;Utility.aspx.&lt;br /&gt;BE CAREFUL NOT TO DISTRIBUTE COPYRIGHTED FONTS&lt;br /&gt;Most font files are licensed pieces of software. They are not typically sold. Most do&lt;br /&gt;not allow distribution of fonts in any applications, even games. This even includes&lt;br /&gt;distributing bitmap reproductions of the fonts and many of the fonts that are distributed&lt;br /&gt;with Microsoft Windows. Be careful not to distribute any copyrighted fonts with&lt;br /&gt;your game.&lt;br /&gt;Importing TrueType Fonts&lt;br /&gt;We want our library to handle fonts, so we will add a TrueType font to our XELibrary&lt;br /&gt;project. We need to create a Fonts subfolder under our Content folder in our XELibrary&lt;br /&gt;project. We can import TrueType fonts by following these steps:&lt;br /&gt;1. Right-click the Fonts subfolder and click Add.&lt;br /&gt;2. Click New Item and choose Sprite Font. We can name our file Arial.spritefont. This&lt;br /&gt;will open the newly created .spritefont XML file.&lt;br /&gt;188 CHAPTER 9 2D Basics&lt;br /&gt;3. In the .spritefont XML file we can change the FontName element to the friendly&lt;br /&gt;name of the font we want to load, Arial.&lt;br /&gt;TIP&lt;br /&gt;We can find the name of our font by looking in the Fonts folder in the Control Panel.&lt;br /&gt;We can use any TrueType font but we cannot use bitmap (.fon) fonts.&lt;br /&gt;4. (Optional) We can change the Size element to be the point size we want the font to&lt;br /&gt;be. We can also scale the font, which we will see later.&lt;br /&gt;5. (Optional) We can change the Spacing element, which specifies the number of&lt;br /&gt;pixels there should be between each character in our font.&lt;br /&gt;6. (Optional) We can change the Style element, which specifies how the font should&lt;br /&gt;be styled. This value is case sensitive and can be the following values: Regular, Bold,&lt;br /&gt;Italic, or Bold Italic.&lt;br /&gt;7. The CharacterRegions element contains the start and end characters that should be&lt;br /&gt;generated and available for drawing.&lt;br /&gt;Now that we have added this spritefont file, when we compile our code the compiler will&lt;br /&gt;generate the resource needed so we can utilize the font in our game. The XML file is&lt;br /&gt;simply a description to the compiler as to which TrueType font to grab and which characters&lt;br /&gt;to create in the .xnb file.&lt;br /&gt;Creating Bitmap Fonts&lt;br /&gt;Not only can we use TrueType font resources, we can make our own bitmap fonts to be&lt;br /&gt;used. To do this we need to actually create the bitmap. We can either do it by hand or by&lt;br /&gt;using the Bitmap Font Maker Utility mentioned at the beginning of this section. After&lt;br /&gt;getting the base bitmap generated, we can modify it in our favorite paint program.&lt;br /&gt;The background of the image must be a fully opaque, pure magenta color (R: 255, G: 0,&lt;br /&gt;B: 255, A: 255). It needs to include an alpha channel that specifies which parts of&lt;br /&gt;the characters are visible. Once the image is created or modified we can import the&lt;br /&gt;image into our Fonts subfolder. XNA Game Studio Express will think it is just a normal&lt;br /&gt;texture so we need to modify the Content Processor value in our properties panel to be&lt;br /&gt;Font Texture.&lt;br /&gt;Drawing 2D Text&lt;br /&gt;Now that we have our font imported we can actually use it. We are not going to create a&lt;br /&gt;demo for this. Instead, we are going to modify our ProgressBarDemo project and have it&lt;br /&gt;display the text Loading … right above the progress bar. We need to add the following&lt;br /&gt;private member fields:&lt;br /&gt;private Vector2 loadingPosition = new Vector2(150, 120);&lt;br /&gt;private SpriteFont font;&lt;br /&gt;Using Sprite Fonts 189&lt;br /&gt;9&lt;br /&gt;We already added the font to our XELibrary project. We could have added it to our game,&lt;br /&gt;but it is most likely we will want to print text out on the screen in the future so now we&lt;br /&gt;have it loaded and don’t need to worry about it any more. However, we need to actually&lt;br /&gt;load the font to our game. We do this just like any other content inside of our&lt;br /&gt;LoadGraphicsContent method:&lt;br /&gt;font = content.Load&lt;SpriteFont&gt;(@”Content\Fonts\Arial”);&lt;br /&gt;Finally, inside of our Draw method, above our call to end our sprite batch, we need to add&lt;br /&gt;the following statement:&lt;br /&gt;spriteBatch.DrawString(font, “Loading ...”, loadingPosition, Color.White);&lt;br /&gt;We can run our ProgressBarDemo and see the word Loading … displayed above our&lt;br /&gt;progress bar. Things are shaping up nicely!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-2185782840642852010?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/2185782840642852010/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=2185782840642852010' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/2185782840642852010'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/2185782840642852010'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/using-sprite-fonts.html' title='Using Sprite Fonts'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-2648944553897756266</id><published>2008-04-04T21:07:00.004-07:00</published><updated>2008-04-04T21:08:25.431-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='basic'/><category scheme='http://www.blogger.com/atom/ns#' term='2d'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>2D Basics</title><content type='html'>The XNA Framework not only provides easy ways for us&lt;br /&gt;to utilize 3D objects, but it also provides excellent 2D&lt;br /&gt;support. There are actually a couple of ways we can achieve&lt;br /&gt;2D inside of XNA. There is true 2D, which is sprite manipulation.&lt;br /&gt;We will discuss this kind of 2D. The other kind is&lt;br /&gt;actually setting up a 3D environment, but locking the&lt;br /&gt;camera so that it is always looking at the same angle and&lt;br /&gt;cannot be moved—it is a 3D world with a stationary&lt;br /&gt;camera.&lt;br /&gt;Whereas 3D uses models to display our scene, 2D uses&lt;br /&gt;images to create and animate our scene. The two dimensions&lt;br /&gt;are x and y—there is no z in 2D. It is very common&lt;br /&gt;to mix 2D and 3D into the same game. Scores, menus, and&lt;br /&gt;timers are examples of things that are typically 2D in a 3D&lt;br /&gt;world. Even if you are not interested in writing 2D games,&lt;br /&gt;the next three chapters will prove beneficial, as there will&lt;br /&gt;be things that can be incorporated into your 3D masterpieces.&lt;br /&gt;Sprite Batches&lt;br /&gt;First we need to understand the term sprite. A sprite is an&lt;br /&gt;image. XNA represents sprites with a Texture2D object. We&lt;br /&gt;load them just like we load textures for our 3D applications,&lt;br /&gt;as they are both images and get processed the same&lt;br /&gt;way. The difference is that in 3D we texture an object with&lt;br /&gt;the image, whereas in 2D we draw the image (or part of the&lt;br /&gt;image) on the screen. We saw an example of drawing part&lt;br /&gt;of an image in the last chapter. We applied different parts&lt;br /&gt;of an image to our skybox. The concept is the same, but&lt;br /&gt;the process is a little different. Really, we just pass in whole&lt;br /&gt;numbers instead of floats. Sprites are represented by x and&lt;br /&gt;y and as such have int values. It is impossible to draw&lt;br /&gt;something at pixel location 0.3, 0.3. If these types of values&lt;br /&gt;172 CHAPTER 9 2D Basics&lt;br /&gt;are passed in, XNA will do some anti-aliasing to make it appear that it is partially in the&lt;br /&gt;pixel area but the actual image location is rounded to a whole number.&lt;br /&gt;We discussed the 3D coordinate system earlier and now we discuss the 2D coordinate&lt;br /&gt;system. The top left of the screen is the origin of the screen (0,0). The x axis runs horizontally&lt;br /&gt;at the top of the screen and the y axis runs vertically down the left side of the&lt;br /&gt;screen. It is identical to how a texture’s coordinate system is used. The difference is that&lt;br /&gt;instead of running from 0.0 to 1.0 like in a texture, the values run from 0 to the width&lt;br /&gt;and height of the screen. So if the resolution is 1024 x 768, the x values would run from&lt;br /&gt;0,0 to 1024,0. The y values would run from 0,0 to 0,768. x runs from left to right and y&lt;br /&gt;runs from top to bottom. The bottom right pixel of the screen would be 1024,768. This&lt;br /&gt;can be seen in Figure 9.1.&lt;br /&gt;x+&lt;br /&gt;y+&lt;br /&gt;(0,0) (1024,0)&lt;br /&gt;(0,768) (1024,768)&lt;br /&gt;FIGURE 9.1 The 2D coordinate system origin is the top left of the screen.&lt;br /&gt;Although the origin of the screen is 0,0 the origin of a sprite may or may not be. The&lt;br /&gt;default is 0,0 but the origin can be overridden if needed. When we draw sprites to the&lt;br /&gt;screen we need to be aware of where the origin of the sprite is because when we pass in a&lt;br /&gt;coordinate (via a Vector2 type), XNA will draw the object to that location starting with&lt;br /&gt;the origin of the sprite. So if we drew the sprite at location 100,200 and we did not touch&lt;br /&gt;the origin of the sprite, then the top left of the sprite would get drawn in 100,200. If we&lt;br /&gt;wanted 100,200 to be the center then we would either need to define the origin of our&lt;br /&gt;sprite or we would need to offset our position manually. When we rotate our sprites, they&lt;br /&gt;will rotate around the origin of the sprite. When we need to rotate our sprites we will&lt;br /&gt;typically set the origin of the sprite to be the center of the sprite. This way the sprite will&lt;br /&gt;rotate around the center. Otherwise, the sprite would rotate around 0,0. The differences&lt;br /&gt;between these two can be seen in Figure 9.2.&lt;br /&gt;We can also scale a sprite. Scaling comes in three different flavors. We can either give a&lt;br /&gt;number to scale the entire sprite by or we can just scale one portion of the sprite. The&lt;br /&gt;final way we can scale is to specify a source rectangle and then specify a destination&lt;br /&gt;rectangle. XNA can scale our source rectangle to fit into our destination rectangle.&lt;br /&gt;Sprite batches are simply batches of sprites. When we draw a lot of sprites on the screen it&lt;br /&gt;can put a load on the machine as we have to send a separate instruction to the graphics&lt;br /&gt;card each time we draw something to the screen. With a sprite batch we have the ability&lt;br /&gt;to batch up our draw functions to happen within the same settings and send one draw&lt;br /&gt;call to the graphics card. When we create a SpriteBatch in our code we can pass in the&lt;br /&gt;following values to its Begin method: SpriteBlendMode, SpriteSortMode, and&lt;br /&gt;SaveStateMode.&lt;br /&gt;Sprite Blend Modes&lt;br /&gt;The blend mode can be set to AlphaBlend, Additive, and None. The default blend mode is&lt;br /&gt;AlphaBlend. AlphaBlend does just that: It blends the sprites drawn (source) with the pixels&lt;br /&gt;it is being drawn on (destination) based on the alpha value of both. This includes transparency&lt;br /&gt;but can be used to create different effects depending on blend values we provide.&lt;br /&gt;We will cover overriding the blending values in the next chapter. Additive is another&lt;br /&gt;common blend mode that XNA provides support for with our sprite batches automatically.&lt;br /&gt;Finally, None simply does not set any blending modes. It just overwrites the destination&lt;br /&gt;area with the source sprite.&lt;br /&gt;Alpha blending is used for normal translucent things like glass, windows, water, and&lt;br /&gt;objects that fade in or out. Additive blending, on the other hand, is good to use when&lt;br /&gt;creating glowing objects like explosions, sparks, and even magic effects. We will discuss&lt;br /&gt;these two blending modes and even more that are not directly supported by sprite&lt;br /&gt;batches in the next chapter.&lt;br /&gt;Sprite Sort Modes&lt;br /&gt;The sort mode determines how different sprites that are drawn actually get displayed on&lt;br /&gt;the screen. In previous times, game developers had to take great care with how they&lt;br /&gt;displayed images to the screen to make sure the background did overwrite their foreground&lt;br /&gt;and that textures with alpha values rendered correctly. Although we still need to&lt;br /&gt;take care as we approach this task, a lot of work has been done for us so that we need to&lt;br /&gt;worry about it less. We still need to be aware of how XNA handles this for us so we can&lt;br /&gt;use it effectively and keep our frame rates high.&lt;br /&gt;Sprite Batches 173&lt;br /&gt;9&lt;br /&gt;FIGURE 9.2 The origin of the sprite determines how the sprite will be rotated.&lt;br /&gt;The sort mode can be set to BackToFront, Deferred, FrontToBack, Immediate, and&lt;br /&gt;Texture. The sort mode defaults to Deferred when we call Begin with no parameters.&lt;br /&gt;Immediate is faster than Deferred. Immediate works a little different than the rest of the&lt;br /&gt;sort modes. Immediate updates the graphics device settings immediately when the Begin&lt;br /&gt;method is called. Then as sprites are drawn to the screen they immediately appear with&lt;br /&gt;no sorting. This is the fastest method available, but it requires us to sort the images the&lt;br /&gt;way we want them to be displayed. We draw the background images first and move up to&lt;br /&gt;the foreground. An interesting thing we can do with immediate mode is change our&lt;br /&gt;graphics device settings after Begin is called and before we actually draw our sprites to the&lt;br /&gt;screen. We will discuss this in more detail in the next chapter.&lt;br /&gt;The rest of the sort modes will update the graphics device settings when End is called on&lt;br /&gt;the SpriteBatch instead of Begin. This means there is only one call out to the graphics&lt;br /&gt;device. The Deferred sort mode is like Immediate in that it does not do any sorting, it just&lt;br /&gt;defers talking to the graphics device until the end of the process.&lt;br /&gt;The next two sort modes are BackToFront and FrontToBack. When we draw our sprites we&lt;br /&gt;can set our layer depth of that sprite. That value is a float between 0.0 and 1.0. The sprites&lt;br /&gt;will draw in this order for the two modes. BackToFront is typically used for transparent&lt;br /&gt;sprites and FrontToBack is typically used for nontransparent (opaque) sprites.&lt;br /&gt;Finally, we can pass in Texture as a sort mode to our sprite batch’s Begin method. The&lt;br /&gt;Texture sort mode will check to see all of the draws that are required and will sort them&lt;br /&gt;so that the graphics device does not need to have its texture changed for each draw if&lt;br /&gt;possible. For example, if we have five sprites drawing and three of them use the same&lt;br /&gt;texture (could be different parts of the same texture) then the graphics device is sent the&lt;br /&gt;texture and then the three draws. Then the other two draws occur with their textures.&lt;br /&gt;This can really help performance. However, we might need foreground and background&lt;br /&gt;images in the same texture. Sorting by texture alone is going to give us good performance,&lt;br /&gt;but we need to also sort by our layer depth. Fortunately, we can set up two sprite&lt;br /&gt;batches at the same time (as long as we are not using Immediate sort mode).&lt;br /&gt;So we could have our first batch sort by texture and our second batch sort by layer depth&lt;br /&gt;(BackToFront or FrontToBack). We can then draw our items including the layer depth&lt;br /&gt;value, and as long as we call End on our sprite batches in the appropriate order our screen&lt;br /&gt;will display as we expect and the performance will be good as well. Because the End&lt;br /&gt;method is what actually does the drawing, we need to make sure we call them in order&lt;br /&gt;from background to foreground. It is best to draw our opaque sprites first in one batch&lt;br /&gt;and then our transparent sprites after that.&lt;br /&gt;Save State Modes&lt;br /&gt;As we complete different tasks inside of our Draw method, we might need to change&lt;br /&gt;settings on our graphics device. For example, we might want our depth buffer to be on&lt;br /&gt;when we are drawing certain items and off when drawing other items. When the sprite&lt;br /&gt;batch is executed (when Begin is called in Immediate sort mode, when End is called for all&lt;br /&gt;others) the graphics device will have the properties in Table 9.1 modified. We might want&lt;br /&gt;to save our properties so we can reset them when the sprite batch is done.&lt;br /&gt;174 CHAPTER 9 2D Basics&lt;br /&gt;SaveStateMode.SaveState does exactly that. The other option is SaveStateMode.None,&lt;br /&gt;which is the default and does not save any state. It is quicker if we just reset the states&lt;br /&gt;ourselves if needed, especially on the Xbox 360.&lt;br /&gt;TABLE 9.1 The SpriteBatch.Begin Method Modifies These Graphics Device Properties&lt;br /&gt;Property Value&lt;br /&gt;RenderState.CullMode CullCounterClockwiseFace&lt;br /&gt;RenderState.DepthBufferEnable False&lt;br /&gt;RenderState.AlphaBlendEnable True&lt;br /&gt;RenderState.AlphaTestEnable True&lt;br /&gt;RenderState.AlphaBlendOperation Add&lt;br /&gt;RenderState.SourceBlend SourceAlpha&lt;br /&gt;RenderState.DestinationBlend InverseSourceAlpha&lt;br /&gt;RenderState.SeparateAlphaBlendEnabled False&lt;br /&gt;RenderState.AlphaFunction Greater&lt;br /&gt;RenderState.ReferenceAlpha 0&lt;br /&gt;SamplerStates[0].AddressU Clamp&lt;br /&gt;SamplerStates[0].AddressV Clamp&lt;br /&gt;SamplerStates[0].MagFilter Linear&lt;br /&gt;SamplerStates[0].MinFilter Linear&lt;br /&gt;SamplerStates[0].MipFilter Linear&lt;br /&gt;SamplerStates[0].MipMapLevelOfDetailBias 0&lt;br /&gt;SamplerStates[0].MaxMipLevel 0&lt;br /&gt;When we mix 2D and 3D together we will definitely want to set the following properties&lt;br /&gt;before drawing our 3D content:&lt;br /&gt;GraphicsDevice.RenderState.DepthBufferEnable = true;&lt;br /&gt;GraphicsDevice.RenderState.AlphaBlendEnable = false;&lt;br /&gt;GraphicsDevice.RenderState.AlphaTestEnable = false;&lt;br /&gt;GraphicsDevice.SamplerStates[0].AddressU = TextureAddressMode.Wrap;&lt;br /&gt;GraphicsDevice.SamplerStates[0].AddressV = TextureAddressMode.Wrap;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-2648944553897756266?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/2648944553897756266/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=2648944553897756266' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/2648944553897756266'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/2648944553897756266'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/2d-basics.html' title='2D Basics'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-6681855199152805851</id><published>2008-04-04T21:07:00.003-07:00</published><updated>2008-04-04T21:07:52.983-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='use'/><category scheme='http://www.blogger.com/atom/ns#' term='using skybox'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>Using the Skybox</title><content type='html'>We have gone through a lot of work, but we are almost done. All we need to do now is&lt;br /&gt;actually use this Skybox object inside of our game. Let’s open the Game1.cs file and add&lt;br /&gt;this private member field:&lt;br /&gt;private Skybox skybox;&lt;br /&gt;Now we need to add a skybox texture to our content folder. Let’s create another subfolder&lt;br /&gt;under Content and call it Skyboxes. This is not required but it might be helpful to remind&lt;br /&gt;us to change the processor type, which we will see how to do shortly. For now, we need&lt;br /&gt;to actually add an image to this Skyboxes subfolder. We can find one on this book’s CD&lt;br /&gt;under the Load3DObject\Content\Skyboxes\skybox.tga inside of the Chapter 8 source&lt;br /&gt;code folder. Copy this texture and paste it into the Skyboxes folder through Solution&lt;br /&gt;Explorer. Inside of the properties window we need to tell XNA Game Studio Express&lt;br /&gt;165&lt;br /&gt;8&lt;br /&gt;LISTING 8.4 Continued&lt;br /&gt;Using the Skybox&lt;br /&gt;which importer and processor we want it to use when loading this content. We will leave&lt;br /&gt;the importer alone as it is defaulted to Texture – XNA Framework. See the sidebar&lt;br /&gt;“Creating a Custom Content Pipeline Importer.”&lt;br /&gt;We will change the Content Processor property, but before we do we need to tell our&lt;br /&gt;project that there is a custom processor of which it needs to be aware. We do this by&lt;br /&gt;double-clicking the Properties tree node under our game projects. Inside of our project&lt;br /&gt;properties we can open the last tab on the bottom: Content Pipeline. We can click Add&lt;br /&gt;and browse to our pipeline project, then add the assembly in the bin folder.&lt;br /&gt;We will add this exact same assembly (under the x86 subfolder) to our Xbox 360 game&lt;br /&gt;project as well. This is because the assembly is only run on our PC when we are actually&lt;br /&gt;building our project. However, we do need to make sure that our XELibrary_Xbox360&lt;br /&gt;assembly has the same name as our Windows assembly. This is important because we&lt;br /&gt;have told the SkyboxWriter where to find the Skybox type and the SkyboxReader object.&lt;br /&gt;We told it XELibrary, not XELibrary_Xbox360.&lt;br /&gt;Alternatively, we could have left the assembly names different and added a condition to&lt;br /&gt;our GetRuntimeReader method in our SkyboxCompiler class. We could have returned a&lt;br /&gt;different string depending on the target platform that is passed into that method.&lt;br /&gt;Now that we have added our Content Pipeline extension to our game projects we can&lt;br /&gt;select SkyboxProcessor from the list of content processors that are available in the property&lt;br /&gt;window when we have our skybox texture selected.&lt;br /&gt;CREATING A CUSTOM CONTENT PIPELINE IMPORTER&lt;br /&gt;An example of setting up a custom importer is the following code:&lt;br /&gt;[ContentImporterAttribute(“.ext”, DefaultProcessor = “SomeCustomProcessor”)]&lt;br /&gt;public class CustomImporter : ContentImporter&lt;CustomType&gt;&lt;br /&gt;{&lt;br /&gt;public override CustomType Import(string filename,&lt;br /&gt;ContentImporterContext context)&lt;br /&gt;{&lt;br /&gt;byte[] data = File.ReadAllBytes(filename);&lt;br /&gt;return (new CustomType(data));&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;This code is a theoretical importer that would be inside of the pipeline project if we&lt;br /&gt;needed to import a type of file that the Content Pipeline could not handle. We could&lt;br /&gt;open up the file that was being loaded by the Content Pipeline and extract the data to&lt;br /&gt;our CustomType that could handle the data. This CustomType would also be used as&lt;br /&gt;the input inside of our processor object (where we used Texture2DContent). The&lt;br /&gt;reason we did not make our own importer is because the XNA Framework’ s Content&lt;br /&gt;Pipeline can handle texture files automatically.&lt;br /&gt;166 CHAPTER 8 Extending the Content Pipeline&lt;br /&gt;We are finally ready to run our game. We should see a star-filled background instead of&lt;br /&gt;our typical CornflowerBlue background. We have successfully built a Content Pipeline&lt;br /&gt;extension that takes a texture file and creates a skybox for us automatically. There is no&lt;br /&gt;limit to the things we can accomplish because of the Content Pipeline’s opened architecture.&lt;br /&gt;We could create a level editor and save it in any format and load it in at compile&lt;br /&gt;time to our game. We could write an importer for our favorite 3D model file type and&lt;br /&gt;work directly with the files. There are many opportunities to use the Content Pipeline.&lt;br /&gt;Whenever we can take a hit up front at build time instead of runtime is always a good&lt;br /&gt;thing.&lt;br /&gt;&lt;br /&gt;Debugging the Content Pipeline Extension&lt;br /&gt;Extending the pipeline is excellent, but what happens when something goes awry? We&lt;br /&gt;cannot exactly step through the code because this is a component being loaded and run&lt;br /&gt;by the IDE … or can we? Fortunately, we can. We discuss how to do that in this section.&lt;br /&gt;If we have the SkyboxPipeline solution opened, we can close it and then add the project&lt;br /&gt;to our Load3DDemo solution. This is not required to debug, but it can make it easier to&lt;br /&gt;make sure the IDE is using the latest changes to the pipeline processor. Alternatively, we&lt;br /&gt;could compile and change the stand-alone SkyboxPipeline solution and then compile the&lt;br /&gt;Load3DDemo. Again, it really is just personal preference.&lt;br /&gt;The goal is to make sure our SkyboxPipeline code gets compiled before our game code. To&lt;br /&gt;do this we can either add the dependency directly to our game code or we can add it to&lt;br /&gt;our XELibrary knowing that our game code already has a dependency on the XELibrary.&lt;br /&gt;We can right-click our XELibrary projects (one at a time) and select Project Dependencies.&lt;br /&gt;We can then add the check box to our SkyboxPipeline project. From now on, when we&lt;br /&gt;compile, the solution will compile the SkyboxPipeline first, followed by the XELibrary&lt;br /&gt;and finally compile our Load3DObject project.&lt;br /&gt;Now that the SkyboxPipeline project is open, we can add the following line of code at the&lt;br /&gt;top of the Process method inside of our SkyboxProcessor class:&lt;br /&gt;System.Diagnostics.Debugger.Launch();&lt;br /&gt;This will actually launch the debugger so we can step through the code to see what is&lt;br /&gt;happening. If we run our program with this line of coded added, the CLR debugger will&lt;br /&gt;get executed. We can then walk through the code like any other. We cannot edit and&lt;br /&gt;continue just like we cannot do that on the Xbox 360. Regardless, being able to step&lt;br /&gt;through the code at runtime is very beneficial. We can set break points wherever we need&lt;br /&gt;to. This is an excellent way to visualize exactly which pieces of code are calling other&lt;br /&gt;pieces and see the general flow of the Content Pipeline.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-6681855199152805851?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/6681855199152805851/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=6681855199152805851' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/6681855199152805851'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/6681855199152805851'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/using-skybox.html' title='Using the Skybox'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-2777726786609187529</id><published>2008-04-04T21:07:00.001-07:00</published><updated>2008-04-04T21:07:29.421-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='create'/><category scheme='http://www.blogger.com/atom/ns#' term='creating skybox'/><title type='text'>Creating a Skybox</title><content type='html'>We want to add a skybox to our code. We are going to&lt;br /&gt;create a project that will contain the content, content&lt;br /&gt;processor, and content compiler. After creating this project&lt;br /&gt;we will create another file inside of our XELibrary to read&lt;br /&gt;the skybox data. Finally, we will create a demo that will&lt;br /&gt;utilize the XELibrary’s Skybox Content Reader, which the&lt;br /&gt;Content Manager uses to consume the skybox.&lt;br /&gt;Before we actually create the project we should first&lt;br /&gt;examine a skybox and its purpose in games. A skybox&lt;br /&gt;keeps us from having to create complex geometry for&lt;br /&gt;objects that are very far away. For example, we do not need&lt;br /&gt;to create a sun or a moon or some distant city when we use&lt;br /&gt;a skybox. We can create six textures that we can put into&lt;br /&gt;our cube. Although there are skybox models we could use,&lt;br /&gt;154 CHAPTER 8 Extending the Content Pipeline&lt;br /&gt;for this chapter we are going to build our own skybox. It is simply a cube and we already&lt;br /&gt;have the code in place to create a cube. We know how to create rectangles and we know&lt;br /&gt;how to position them where we want them. We can create six rectangles that we can use&lt;br /&gt;as our skybox. When each texture is applied to each side of the skybox we get an effect&lt;br /&gt;that our world is much bigger than it is. Plus, it looks much better than the cornflower&lt;br /&gt;blue backdrop we currently have!&lt;br /&gt;Creating the Skybox Content Object&lt;br /&gt;To start, let’s create a new Windows library project called SkyboxPipeline. There is no&lt;br /&gt;need to create an Xbox 360 version of the project because this will only be run on the PC.&lt;br /&gt;This SkyboxPipeline project will have three files. The first file is the SkyboxContent.cs&lt;br /&gt;code file, shown in Listing 8.1.&lt;br /&gt;LISTING 8.1 SkyboxContent.cs holds the design time class of our skybox&lt;br /&gt;using System;&lt;br /&gt;using Microsoft.Xna.Framework.Content.Pipeline.Processors;&lt;br /&gt;using Microsoft.Xna.Framework.Content.Pipeline.Graphics;&lt;br /&gt;namespace SkyboxPipeline&lt;br /&gt;{&lt;br /&gt;public class SkyboxContent&lt;br /&gt;{&lt;br /&gt;public ModelContent Model;&lt;br /&gt;public Texture2DContent Texture;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;The SkyboxContent object holds our skybox data at design time. We need to add a reference&lt;br /&gt;to Microsoft.Xna.Framework.Content.Pipeline to our project to utilize the namespaces&lt;br /&gt;needed.&lt;br /&gt;Creating the Skybox Processor&lt;br /&gt;The SkyboxContent object is utilized by the processor, shown in Listing 8.2.&lt;br /&gt;LISTING 8.2 SkyboxProcessor.cs actually processes the data it gets as input from the&lt;br /&gt;Content Pipeline&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using Microsoft.Xna.Framework;&lt;br /&gt;using Microsoft.Xna.Framework.Content.Pipeline;&lt;br /&gt;using Microsoft.Xna.Framework.Content.Pipeline.Graphics;&lt;br /&gt;using Microsoft.Xna.Framework.Content.Pipeline.Processors;&lt;br /&gt;namespace SkyboxPipeline&lt;br /&gt;{&lt;br /&gt;[ContentProcessor]&lt;br /&gt;class SkyboxProcessor : ContentProcessor&lt;Texture2DContent, SkyboxContent&gt;&lt;br /&gt;{&lt;br /&gt;private int width = 1024;&lt;br /&gt;private int height = 512;&lt;br /&gt;private int cellSize = 256;&lt;br /&gt;public override SkyboxContent Process(Texture2DContent input,&lt;br /&gt;ContentProcessorContext context)&lt;br /&gt;{&lt;br /&gt;MeshBuilder builder = MeshBuilder.StartMesh(“XESkybox”);&lt;br /&gt;CreatePositions(ref builder);&lt;br /&gt;AddVerticesInformation(ref builder);&lt;br /&gt;// Create the output object.&lt;br /&gt;SkyboxContent skybox = new SkyboxContent();&lt;br /&gt;// Finish making the mesh&lt;br /&gt;MeshContent skyboxMesh = builder.FinishMesh();&lt;br /&gt;//Compile the mesh we just built through the default ModelProcessor&lt;br /&gt;skybox.Model = context.Convert&lt;MeshContent, ModelContent&gt;(&lt;br /&gt;skyboxMesh, “ModelProcessor”);&lt;br /&gt;skybox.Texture = input;&lt;br /&gt;return skybox;&lt;br /&gt;}&lt;br /&gt;private void CreatePositions(ref MeshBuilder builder)&lt;br /&gt;{&lt;br /&gt;Vector3 position;&lt;br /&gt;//————-front plane&lt;br /&gt;//top left&lt;br /&gt;position = new Vector3(-1, 1, 1);&lt;br /&gt;builder.CreatePosition(position); //0&lt;br /&gt;//bottom right&lt;br /&gt;155&lt;br /&gt;8&lt;br /&gt;LISTING 8.2 Continued&lt;br /&gt;Creating a Skybox&lt;br /&gt;position = new Vector3(1, -1, 1);&lt;br /&gt;builder.CreatePosition(position); //1&lt;br /&gt;//bottom left&lt;br /&gt;position = new Vector3(-1, -1, 1);&lt;br /&gt;builder.CreatePosition(position); //2&lt;br /&gt;//top right&lt;br /&gt;position = new Vector3(1, 1, 1);&lt;br /&gt;builder.CreatePosition(position); //3&lt;br /&gt;//————-back plane&lt;br /&gt;//top left&lt;br /&gt;position = new Vector3(-1, 1, -1); //4&lt;br /&gt;builder.CreatePosition(position);&lt;br /&gt;//bottom right&lt;br /&gt;position = new Vector3(1, -1, -1); //5&lt;br /&gt;builder.CreatePosition(position);&lt;br /&gt;//bottom left&lt;br /&gt;position = new Vector3(-1, -1, -1); //6&lt;br /&gt;builder.CreatePosition(position);&lt;br /&gt;//top right&lt;br /&gt;position = new Vector3(1, 1, -1); //7&lt;br /&gt;builder.CreatePosition(position);&lt;br /&gt;}&lt;br /&gt;private Vector2 UV(int u, int v, Vector2 cellIndex)&lt;br /&gt;{&lt;br /&gt;return(new Vector2((cellSize * (cellIndex.X + u) / width),&lt;br /&gt;(cellSize * (cellIndex.Y + v) / height)));&lt;br /&gt;}&lt;br /&gt;private void AddVerticesInformation(ref MeshBuilder builder)&lt;br /&gt;{&lt;br /&gt;//texture locations:&lt;br /&gt;//F,R,B,L&lt;br /&gt;//U,D&lt;br /&gt;//Front&lt;br /&gt;Vector2 fi = new Vector2(0, 0); //cell 0, row 0&lt;br /&gt;156 CHAPTER 8 Extending the Content Pipeline&lt;br /&gt;LISTING 8.2 Continued&lt;br /&gt;//Right&lt;br /&gt;Vector2 ri = new Vector2(1, 0); //cell 1, row 0&lt;br /&gt;//Back&lt;br /&gt;Vector2 bi = new Vector2(2, 0); //cell 2, row 0&lt;br /&gt;//Left&lt;br /&gt;Vector2 li = new Vector2(3, 0); //cell 3, row 0&lt;br /&gt;//Upward (Top)&lt;br /&gt;Vector2 ui = new Vector2(0, 1); //cell 0, row 1&lt;br /&gt;//Downward (Bottom)&lt;br /&gt;Vector2 di = new Vector2(1, 1); //cell 1, row 1&lt;br /&gt;int texCoordChannel = builder.CreateVertexChannel&lt;Vector2&gt;&lt;br /&gt;(VertexChannelNames.TextureCoordinate(0));&lt;br /&gt;//————front plane first column, first row&lt;br /&gt;//bottom triangle of front plane&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(0, 0, fi));&lt;br /&gt;builder.AddTriangleVertex(4); //-1,1,1&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(1, 1, fi));&lt;br /&gt;builder.AddTriangleVertex(5); //1,-1,1&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(0, 1, fi));&lt;br /&gt;builder.AddTriangleVertex(6); //-1,-1,1&lt;br /&gt;//top triangle of front plane&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(0, 0, fi));&lt;br /&gt;builder.AddTriangleVertex(4); //-1,1,1&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(1, 0, fi));&lt;br /&gt;builder.AddTriangleVertex(7); //1,1,1&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(1, 1, fi));&lt;br /&gt;builder.AddTriangleVertex(5); //1,-1,1&lt;br /&gt;//————-right plane&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(1, 0, ri));&lt;br /&gt;builder.AddTriangleVertex(3);&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(1, 1, ri));&lt;br /&gt;builder.AddTriangleVertex(1);&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(0, 1, ri));&lt;br /&gt;builder.AddTriangleVertex(5);&lt;br /&gt;Creating a Skybox 157&lt;br /&gt;8&lt;br /&gt;LISTING 8.2 Continued&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(1, 0, ri));&lt;br /&gt;builder.AddTriangleVertex(3);&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(0, 1, ri));&lt;br /&gt;builder.AddTriangleVertex(5);&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(0, 0, ri));&lt;br /&gt;builder.AddTriangleVertex(7);&lt;br /&gt;//————-back pane //3rd column, first row&lt;br /&gt;//bottom triangle of back plane&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(1, 1, bi)); //1,1&lt;br /&gt;builder.AddTriangleVertex(2); //-1,-1,1&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(0, 1, bi)); //0,1&lt;br /&gt;builder.AddTriangleVertex(1); //1,-1,1&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(1, 0, bi)); //1,0&lt;br /&gt;builder.AddTriangleVertex(0); //-1,1,1&lt;br /&gt;//top triangle of back plane&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(0, 1, bi)); //0,1&lt;br /&gt;builder.AddTriangleVertex(1); //1,-1,1&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(0, 0, bi)); //0,0&lt;br /&gt;builder.AddTriangleVertex(3); //1,1,1&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(1, 0, bi)); //1,0&lt;br /&gt;builder.AddTriangleVertex(0); //-1,1,1&lt;br /&gt;//————-left plane&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(1, 1, li));&lt;br /&gt;builder.AddTriangleVertex(6);&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(0, 1, li));&lt;br /&gt;builder.AddTriangleVertex(2);&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(0, 0, li));&lt;br /&gt;builder.AddTriangleVertex(0);&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(1, 0, li));&lt;br /&gt;builder.AddTriangleVertex(4);&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(1, 1, li));&lt;br /&gt;builder.AddTriangleVertex(6);&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(0, 0, li));&lt;br /&gt;builder.AddTriangleVertex(0);&lt;br /&gt;//————upward (top) plane&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(1, 0, ui));&lt;br /&gt;builder.AddTriangleVertex(3);&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(0, 1, ui));&lt;br /&gt;builder.AddTriangleVertex(4);&lt;br /&gt;158 CHAPTER 8 Extending the Content Pipeline&lt;br /&gt;LISTING 8.2 Continued&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(0, 0, ui));&lt;br /&gt;builder.AddTriangleVertex(0);&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(1, 0, ui));&lt;br /&gt;builder.AddTriangleVertex(3);&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(1, 1, ui));&lt;br /&gt;builder.AddTriangleVertex(7);&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(0, 1, ui));&lt;br /&gt;builder.AddTriangleVertex(4);&lt;br /&gt;//————downward (bottom) plane&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(1, 0, di));&lt;br /&gt;builder.AddTriangleVertex(2);&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(1, 1, di));&lt;br /&gt;builder.AddTriangleVertex(6);&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(0, 0, di));&lt;br /&gt;builder.AddTriangleVertex(1);&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(1, 1, di));&lt;br /&gt;builder.AddTriangleVertex(6);&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(0, 1, di));&lt;br /&gt;builder.AddTriangleVertex(5);&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(0, 0, di));&lt;br /&gt;builder.AddTriangleVertex(1);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;The SkyboxProcessor contains a lot of code, but the vast majority of it is actually building&lt;br /&gt;and texturing our skybox. We can go ahead and create this file in our pipeline project&lt;br /&gt;now.&lt;br /&gt;To begin we used the [ContentProcessor] attribute for our class so the Content Pipeline&lt;br /&gt;could determine which class to call when it needed to process a resource with our type.&lt;br /&gt;We inherit from the ContentProcessor class stating that we are going to be taking a&lt;br /&gt;Texture2D as input and outputting our skybox content type. In the Process method we&lt;br /&gt;take in two parameters: input and context. To create our skybox we are going to pass in a&lt;br /&gt;single texture in our game projects. The processor creates a new MeshBuilder object,&lt;br /&gt;which is a helper class that allows us to quickly create a mesh with vertices in any order&lt;br /&gt;we wish and then apply different vertex information for those vertices that can contain&lt;br /&gt;things like texture coordinates, normals, colors, and so on. For our purposes we will be&lt;br /&gt;storing the texture. We create our actual eight vertices of our skybox cube in the&lt;br /&gt;CreatePositions method. We are simply passing a vertex position into the&lt;br /&gt;CreatePosition method of the MeshBuilder method.&lt;br /&gt;Creating a Skybox 159&lt;br /&gt;8&lt;br /&gt;LISTING 8.2 Continued&lt;br /&gt;Next up is our call to AddVerticesInformation. This method contains the bulk of the&lt;br /&gt;code but it is not doing anything fancy. It is simply creating triangles in the mesh by&lt;br /&gt;passing the vertices index values to the AddTriangleVertex method of the MeshBuilder&lt;br /&gt;object. These vertices need to be called in the right order. We can think of this as&lt;br /&gt;building the indices of the mesh. The idea is that we created our unique vertices (in&lt;br /&gt;CreatePositions) and although we could have stored the value CreatePosition returned&lt;br /&gt;to us, we know that it will return us the next number starting with 0. Instead of using up&lt;br /&gt;memory for the index being passed back, we just made a note in the comment next to&lt;br /&gt;that vertex so we could build our triangles.&lt;br /&gt;Before we actually add a vertex to a triangle of our mesh, we pass in our vertex channel&lt;br /&gt;information. We created a vertex channel before we started creating triangles with the&lt;br /&gt;following code:&lt;br /&gt;int texCoordChannel = builder.CreateVertexChannel&lt;Vector2&gt;&lt;br /&gt;(VertexChannelNames.TextureCoordinate(0));&lt;br /&gt;We can have multiple vertex channels. Although we are only going to store texture coordinates,&lt;br /&gt;we could also store normals, binormals, tangents, weights, and colors. Because we&lt;br /&gt;could store all of these different pieces of information we need to tell the vertex channel&lt;br /&gt;which type of data we are storing. We then store an index to that particular channel.&lt;br /&gt;Once we have that channel index we can call the SetVertexChannelData method for each&lt;br /&gt;triangle vertex we add. In fact, set the channel data for the builder before adding the&lt;br /&gt;vertex. If we had more than one vertex channel to apply to a vertex, we would call all of&lt;br /&gt;them in succession before finally calling the AddTriangleVertex method. The following&lt;br /&gt;code shows the order in which this needs to take place:&lt;br /&gt;builder.SetVertexChannelData(texCoordChannel, UV(0, 0, fi));&lt;br /&gt;builder.AddTriangleVertex(4);&lt;br /&gt;SetVertexChannelData takes in the vertex channel ID followed by the appropriate data&lt;br /&gt;for that channel. When we set up the vertex channel to handle texture coordinates we&lt;br /&gt;did so by passing the generic Vector2 because texture coordinates have an x and a y&lt;br /&gt;component. This means that the SetVertexChannelData for our texture coordinate&lt;br /&gt;channel is expecting a type of Vector2.&lt;br /&gt;For this texture mapping code to make sense, we need to discuss how the texture asset we&lt;br /&gt;are going to pass into our demo or game needs to be laid out. Instead of requiring six&lt;br /&gt;different textures to create a skybox, we are requiring only one with each plane of the&lt;br /&gt;cube to have a specific location inside of the texture. The texture size is 1024 x 512 to&lt;br /&gt;keep with the power-of-two restriction most graphic cards make us live by. We put four&lt;br /&gt;textures on the top row and two textures on the bottom row. The top row will have the&lt;br /&gt;cube faces Front, Right, Back, and Left in that order. The bottom row will have Up (Top)&lt;br /&gt;and Down (Bottom). If we have skyboxes in other formats we can use a paint program to&lt;br /&gt;get them in this format. We can also use tools to generate skybox images and output&lt;br /&gt;them into this format or one we can easily work with. The great thing about this being an&lt;br /&gt;extension of the Content Pipeline is that we have free reign over how we want to read in&lt;br /&gt;160 CHAPTER 8 Extending the Content Pipeline&lt;br /&gt;data and create content that our games can easily use. If we stick with the current single&lt;br /&gt;texture it leaves part of the texture unused. We could utilize these two spots for something&lt;br /&gt;else. For example, we could create one or two cloud layers to our skybox, so instead&lt;br /&gt;of just rendering a cube, it would render a cube with two additional layers that could&lt;br /&gt;prove to be a nice effect. We could use it for terrain generation by reading in the values&lt;br /&gt;from a gray-scaled image in one of those spots to create a nice ground layout. We do not&lt;br /&gt;discuss terrain generation in this book, but there are many excellent articles on the Web&lt;br /&gt;about generating terrains.&lt;br /&gt;Now that we know how the texture is laid out we can discuss some of the details of the&lt;br /&gt;code that is applying the texture to the different panels of the cube. In the following code&lt;br /&gt;we declared a variable to hold our index of the right panel in the texture:&lt;br /&gt;//Right&lt;br /&gt;Vector2 ri = new Vector2(1, 0); //cell 1, row 0&lt;br /&gt;We are storing 1,0 in a vector signifying that the right panel’s portion of the large texture&lt;br /&gt;is in the first cell in row zero (this is zero based). In Chapter 4, “Creating 3D Objects,”&lt;br /&gt;we discussed how to texture our rectangle (quad) by applying different u and v coordinates&lt;br /&gt;to the different vertices of our rectangle. We are using the exact same concept here.&lt;br /&gt;The only difference is that we have to take into account the fact that we are extracting&lt;br /&gt;multiple textures from our one texture. For example, to texture the right-side panel of&lt;br /&gt;our skybox using just one texture we could simply tell the top left vertex to use texture&lt;br /&gt;coordinates 0,0 and the bottom right vertex to use texture coordinate 1,1. However, our&lt;br /&gt;right-side panel’s texture is not the entire texture we have in memory; instead it is from&lt;br /&gt;pixels 256,0 to 512,256. We can see this in Figure 8.1 where the right panel texture is not&lt;br /&gt;grayed out.&lt;br /&gt;Creating a Skybox 161&lt;br /&gt;8&lt;br /&gt;To handle the offset issue we created a UV method that takes in the typical 0 and 1 along&lt;br /&gt;with index cell from which we need to get our updated u and v coordinates. The UV&lt;br /&gt;method that calculates our u and v values is as follows:&lt;br /&gt;private Vector2 UV(int u, int v, Vector2 cellIndex)&lt;br /&gt;{&lt;br /&gt;return(new Vector2((cellSize * (cellIndex.X + u) / width),&lt;br /&gt;(cellSize * (cellIndex.Y + v) / height)));&lt;br /&gt;}&lt;br /&gt;This method simply takes in the u and v coordinates we would normally map on a full&lt;br /&gt;texture along with the cell index we want to access in the texture and it returns the calculated&lt;br /&gt;u and v coordinates. The cellSize, width, and height are private member fields. We&lt;br /&gt;take the size of the cell, 256, and multiply that by the sum of our x value of our cell&lt;br /&gt;index and the u value passed in. We take that value and divide it by width to come up&lt;br /&gt;with the correct u position of the large texture. We do the same thing to get our v value.&lt;br /&gt;We pass those actual values to SetVertexChannelData so it will associate the right texture&lt;br /&gt;coordinates with that vertex.&lt;br /&gt;After actually creating the Skybox vertices and setting up all of the triangles needed and&lt;br /&gt;applying our texture coordinates, we can finally save the mesh. We do this by calling the&lt;br /&gt;FinishMesh method on our MeshBuilder object, which returns a MeshContent type back to&lt;br /&gt;us. This is convenient as that is the type of object we need to pass to the default&lt;br /&gt;ModelProcessor to process our mesh (just as if we loaded a .X file through the Content&lt;br /&gt;Pipeline). This is done with the following code:&lt;br /&gt;MeshContent skyboxMesh = builder.FinishMesh();&lt;br /&gt;skybox.Model = context.Convert&lt;MeshContent, ModelContent&gt;(&lt;br /&gt;skyboxMesh, “ModelProcessor”);&lt;br /&gt;After setting our texture to the texture (our input) that was actually loaded to start this&lt;br /&gt;process, we return the skybox content and the compiler gets launched. We discuss the&lt;br /&gt;compiler in the next section.&lt;br /&gt;Creating the Skybox Compiler&lt;br /&gt;This brings us to our third and final file for our pipeline project. We need to create&lt;br /&gt;another code file with the name SkyboxCompiler.cs. The code for this file is found in&lt;br /&gt;Listing 8.3.&lt;br /&gt;LISTING 8.3 SkyboxCompiler.cs compiles and writes out the content it is passed from the&lt;br /&gt;processor&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using Microsoft.Xna.Framework;&lt;br /&gt;using Microsoft.Xna.Framework.Content.Pipeline.Graphics;&lt;br /&gt;using Microsoft.Xna.Framework.Content.Pipeline.Processors;&lt;br /&gt;162 CHAPTER 8 Extending the Content Pipeline&lt;br /&gt;using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;&lt;br /&gt;namespace SkyboxPipeline&lt;br /&gt;{&lt;br /&gt;[ContentTypeWriter]&lt;br /&gt;public class SkyboxWriter : ContentTypeWriter&lt;SkyboxContent&gt;&lt;br /&gt;{&lt;br /&gt;protected override void Write(ContentWriter output, SkyboxContent value)&lt;br /&gt;{&lt;br /&gt;output.WriteObject(value.Model);&lt;br /&gt;output.WriteObject(value.Texture);&lt;br /&gt;}&lt;br /&gt;public override string GetRuntimeType(TargetPlatform targetPlatform)&lt;br /&gt;{&lt;br /&gt;return “XELibrary.Skybox, “ +&lt;br /&gt;“XELibrary, Version=1.0.0.0, Culture=neutral”;&lt;br /&gt;}&lt;br /&gt;public override string GetRuntimeReader(TargetPlatform targetPlatform)&lt;br /&gt;{&lt;br /&gt;return “XELibrary.SkyboxReader, “ +&lt;br /&gt;“XELibrary, Version=1.0.0.0, Culture=neutral”;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;We start off this class much like the last in that we associate an attribute with it. This&lt;br /&gt;time we need to use the [ContentTypeWriter] attribute as it tells the Content Pipeline&lt;br /&gt;this is the compiler or writer class. We inherit from the ContentTypeWriter with the&lt;br /&gt;generic type of SkyboxContent (which we created in the first file of this project). This way&lt;br /&gt;when the Content Pipeline gets the skybox content back from the processor it knows&lt;br /&gt;where to send the data to be compiled.&lt;br /&gt;We override the Write method and save our skybox as an .xnb file. The base class does all&lt;br /&gt;of the heavy lifting and all we need to do is write our object out. The next method,&lt;br /&gt;GetRuntimeType, tells the Content Pipeline the actual type of the skybox data that will be&lt;br /&gt;loaded at runtime. The last method, GetRuntimeReader, tells the Content Pipeline which&lt;br /&gt;object will actually be reading in and processing the .xnb data. The contents of these two&lt;br /&gt;methods are returning different classes inside of the same assembly. They do not need to&lt;br /&gt;reside in the same assembly, but it definitely made sense in this case. We store the&lt;br /&gt;runtime type and runtime reader in a separate project. We do not add them to the&lt;br /&gt;pipeline project because the pipeline project is Windows dependent and our actual&lt;br /&gt;skybox type and reader object needs to be platform independent. We are going to set&lt;br /&gt;Creating a Skybox 163&lt;br /&gt;8&lt;br /&gt;Creating the Skybox Reader&lt;br /&gt;Let’s copy and open our Load3DObject project from Chapter 6, “Loading and Texturing&lt;br /&gt;3D Objects.” Our XELibrary should already be inside of this project and we can add a&lt;br /&gt;SkyboxReader.cs file to our XELibrary projects. This file will contain both our Skybox type&lt;br /&gt;and our SkyboxReader type. We could have created separate files if we desired. If we had&lt;br /&gt;them in different assemblies, however, we would need to update our GetRunttimeType&lt;br /&gt;and GetRuntimeReader methods in our content writer. The code contained in&lt;br /&gt;SkyboxReader.cs can be found in Listing 8.4.&lt;br /&gt;LISTING 8.4 SkyboxReader.cs inside of our XELibrary allows for our games to read the&lt;br /&gt;compiled .xnb files generated by the Content Pipeline&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using Microsoft.Xna.Framework;&lt;br /&gt;using Microsoft.Xna.Framework.Graphics;&lt;br /&gt;using Microsoft.Xna.Framework.Content;&lt;br /&gt;namespace XELibrary&lt;br /&gt;{&lt;br /&gt;public class SkyboxReader : ContentTypeReader&lt;Skybox&gt;&lt;br /&gt;{&lt;br /&gt;protected override Skybox Read(ContentReader input, Skybox existingInstance)&lt;br /&gt;{&lt;br /&gt;return new Skybox(input);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;public class Skybox&lt;br /&gt;{&lt;br /&gt;private Model skyboxModel;&lt;br /&gt;private Texture2D skyboxTexture;&lt;br /&gt;internal Skybox(ContentReader input)&lt;br /&gt;{&lt;br /&gt;skyboxModel = input.ReadObject&lt;Model&gt;();&lt;br /&gt;skyboxTexture = input.ReadObject&lt;Texture2D&gt;();&lt;br /&gt;}&lt;br /&gt;public void Draw(Matrix view, Matrix projection, Matrix world)&lt;br /&gt;{&lt;br /&gt;foreach (ModelMesh mesh in skyboxModel.Meshes)&lt;br /&gt;{&lt;br /&gt;foreach (BasicEffect be in mesh.Effects)&lt;br /&gt;{&lt;br /&gt;be.Projection = projection;&lt;br /&gt;be.View = view;&lt;br /&gt;be.World = world;&lt;br /&gt;be.Texture = skyboxTexture;&lt;br /&gt;be.TextureEnabled = true;&lt;br /&gt;}&lt;br /&gt;mesh.Draw(SaveStateMode.SaveState);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;Our SkyboxReader class is pretty small. It derives from the ContentTypeReader and uses a&lt;br /&gt;Skybox type that we will see in a moment. We override the Read method of this class,&lt;br /&gt;which gets passed in the skybox data as input as well as an existing instance of the object&lt;br /&gt;that we could write into if needed. We take the input and actually create an instance to&lt;br /&gt;our Skybox object by calling the internal constructor.&lt;br /&gt;Inside of the Skybox class we take the input that was just passed to us and store the model&lt;br /&gt;embedded inside. We expose a Draw method that takes in view, projection, and world&lt;br /&gt;matrices as parameters. We then treat the model as if we loaded it from the pipeline&lt;br /&gt;(because we did) and set the basic effect on each mesh inside of the model to use the&lt;br /&gt;projection, view, and world matrices passed to the object. Finally, we actually draw the&lt;br /&gt;object onto the screen.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-2777726786609187529?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/2777726786609187529/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=2777726786609187529' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/2777726786609187529'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/2777726786609187529'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/creating-skybox.html' title='Creating a Skybox'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-5696697438604990254</id><published>2008-04-04T21:06:00.002-07:00</published><updated>2008-04-04T21:07:00.766-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sound'/><category scheme='http://www.blogger.com/atom/ns#' term='create'/><category scheme='http://www.blogger.com/atom/ns#' term='demo'/><category scheme='http://www.blogger.com/atom/ns#' term='creating'/><title type='text'>Creating a Sound Demo</title><content type='html'>Now we need to add in another Windows game project to our XELibrary solution. We can&lt;br /&gt;call this new project SoundDemo. We can also set up our solution for our Xbox 360&lt;br /&gt;project if we want to test it on the console. Now we need to make sure our game is referencing&lt;br /&gt;the XELibrary project.&lt;br /&gt;Once we have our XELibrary referenced correctly, we can start writing code to test out our&lt;br /&gt;new sound class (and updated input class). We need to use the library’s namespace at the&lt;br /&gt;top of our game class as follows:&lt;br /&gt;using XELibrary;&lt;br /&gt;We should also add a folder called Content with a Sounds subfolder to our solution. We&lt;br /&gt;can then paste our XACT project file into our Sounds folder. The wave files should be put&lt;br /&gt;in the folder, but do not need to be included in the project. When we compile our code&lt;br /&gt;later, the Content Pipeline will find all of the waves from the wave bank and wrap them&lt;br /&gt;into a wave bank .xwb file. It also creates a sound bank .xsb file while the audio engine is&lt;br /&gt;stored in Chapter7.xgs (as that is what we had as our XACT project name).&lt;br /&gt;We will now add in our InputHandler game component so we can kick off sound events&lt;br /&gt;based on our input. We need to declare our private member field to hold the component&lt;br /&gt;as well as adding it to our game’s components collection:&lt;br /&gt;Creating a Sound Demo 147&lt;br /&gt;7&lt;br /&gt;private InputHandler input;&lt;br /&gt;private SoundManager sound;&lt;br /&gt;public Game1()&lt;br /&gt;{&lt;br /&gt;graphics = new GraphicsDeviceManager(this);&lt;br /&gt;content = new ContentManager(Services);&lt;br /&gt;input = new InputHandler(this);&lt;br /&gt;Components.Add(input);&lt;br /&gt;sound = new SoundManager(this, “Chapter7”);&lt;br /&gt;Components.Add(sound);&lt;br /&gt;}&lt;br /&gt;We passed in “Chapter7” to our constructor because that is what we called our XACT&lt;br /&gt;project. The next thing we need to do is set up our playlist. We can do this inside of our&lt;br /&gt;Initialize method because we added the sound component in our constructor:&lt;br /&gt;string[] playList = { “Song1”, “Song2”, “Song3” };&lt;br /&gt;sound.StartPlayList(playList);&lt;br /&gt;The code tells our sound manager we will be playing three different songs. The library&lt;br /&gt;will keep checking to see if they are playing. If not, it will automatically play the next&lt;br /&gt;one, looping back to the beginning song when it reaches the end of the list.&lt;br /&gt;Now we can actually populate our Update method to check for our input to play all of the&lt;br /&gt;sounds and songs we set up in XACT. We need to add the following code to our Update&lt;br /&gt;method:&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.D1) ||&lt;br /&gt;input.ButtonHandler.WasButtonPressed(0, InputHandler.ButtonType.A))&lt;br /&gt;sound.Play(“gunshot”);&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.D2) ||&lt;br /&gt;input.ButtonHandler.WasButtonPressed(0, InputHandler.ButtonType.B))&lt;br /&gt;sound.Play(“hit”);&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.D3) ||&lt;br /&gt;input.ButtonHandler.WasButtonPressed(0,&lt;br /&gt;InputHandler.ButtonType.LeftShoulder))&lt;br /&gt;sound.Play(“attention”);&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.D4) ||&lt;br /&gt;input.ButtonHandler.WasButtonPressed(0,&lt;br /&gt;InputHandler.ButtonType.LeftStick))&lt;br /&gt;sound.Play(“explosion”);&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.D5) ||&lt;br /&gt;input.ButtonHandler.WasButtonPressed(0,&lt;br /&gt;InputHandler.ButtonType.RightShoulder))&lt;br /&gt;148 CHAPTER 7 Sounds and Music&lt;br /&gt;sound.Play(“bullet”);&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.D6) ||&lt;br /&gt;input.ButtonHandler.WasButtonPressed(0,&lt;br /&gt;InputHandler.ButtonType.RightStick))&lt;br /&gt;sound.Play(“crash”);&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.D7) ||&lt;br /&gt;input.ButtonHandler.WasButtonPressed(0, InputHandler.ButtonType.X))&lt;br /&gt;sound.Play(“complex”);&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.D8) ||&lt;br /&gt;input.ButtonHandler.WasButtonPressed(0, InputHandler.ButtonType.Y))&lt;br /&gt;sound.Toggle(“CoolLoop”);&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.D9) ||&lt;br /&gt;input.ButtonHandler.WasButtonPressed(0,&lt;br /&gt;InputHandler.ButtonType.LeftShoulder))&lt;br /&gt;sound.Toggle(“CoolLoop 2”);&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.P) ||&lt;br /&gt;input.ButtonHandler.WasButtonPressed(0, InputHandler.ButtonType.Start))&lt;br /&gt;{&lt;br /&gt;sound.Toggle(“CoolLoop”);&lt;br /&gt;}&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.S) ||&lt;br /&gt;(input.GamePads[0].Triggers.Right &gt; 0))&lt;br /&gt;sound.StopPlayList();&lt;br /&gt;We are simply checking to see if different keys were pressed or different buttons were&lt;br /&gt;pushed. Based on those results we play different cues that we set up in the XACT project.&lt;br /&gt;A good exercise for us would be to run the demo and reread the section of this chapter&lt;br /&gt;where we set up all of these sounds and see if they do what we expect when we press the&lt;br /&gt;appropriate keys or buttons. In particular we can press the B button or number 2 key&lt;br /&gt;repeatedly and see that the “hit” cue is queuing up as we told it to limit itself to only&lt;br /&gt;playing once and to queue failed requests. We can also click down on our right thumb&lt;br /&gt;stick or press the number 6 key to hear our crash. If the playlist is hindering our hearing&lt;br /&gt;of the sounds we can stop it by pressing the S key or pushing on our right trigger.&lt;br /&gt;The final piece of code for our sound demo is where we can set a global variable for the&lt;br /&gt;RPC we set up as well as the volume of our default category cues. To start, we need to add&lt;br /&gt;two more private member fields:&lt;br /&gt;private float currentVolume = 0.5f;&lt;br /&gt;private float value = 0;&lt;br /&gt;Now we can finish up our Update method with the following code:&lt;br /&gt;if (input.KeyboardState.IsHoldingKey(Keys.Up) ||&lt;br /&gt;input.GamePads[0].DPad.Up == ButtonState.Pressed)&lt;br /&gt;Creating a Sound Demo 149&lt;br /&gt;7&lt;br /&gt;&lt;br /&gt;Now we need to add in another Windows game project to our XELibrary solution. We can&lt;br /&gt;call this new project SoundDemo. We can also set up our solution for our Xbox 360&lt;br /&gt;project if we want to test it on the console. Now we need to make sure our game is referencing&lt;br /&gt;the XELibrary project.&lt;br /&gt;Once we have our XELibrary referenced correctly, we can start writing code to test out our&lt;br /&gt;new sound class (and updated input class). We need to use the library’s namespace at the&lt;br /&gt;top of our game class as follows:&lt;br /&gt;using XELibrary;&lt;br /&gt;We should also add a folder called Content with a Sounds subfolder to our solution. We&lt;br /&gt;can then paste our XACT project file into our Sounds folder. The wave files should be put&lt;br /&gt;in the folder, but do not need to be included in the project. When we compile our code&lt;br /&gt;later, the Content Pipeline will find all of the waves from the wave bank and wrap them&lt;br /&gt;into a wave bank .xwb file. It also creates a sound bank .xsb file while the audio engine is&lt;br /&gt;stored in Chapter7.xgs (as that is what we had as our XACT project name).&lt;br /&gt;We will now add in our InputHandler game component so we can kick off sound events&lt;br /&gt;based on our input. We need to declare our private member field to hold the component&lt;br /&gt;as well as adding it to our game’s components collection:&lt;br /&gt;Creating a Sound Demo 147&lt;br /&gt;7&lt;br /&gt;private InputHandler input;&lt;br /&gt;private SoundManager sound;&lt;br /&gt;public Game1()&lt;br /&gt;{&lt;br /&gt;graphics = new GraphicsDeviceManager(this);&lt;br /&gt;content = new ContentManager(Services);&lt;br /&gt;input = new InputHandler(this);&lt;br /&gt;Components.Add(input);&lt;br /&gt;sound = new SoundManager(this, “Chapter7”);&lt;br /&gt;Components.Add(sound);&lt;br /&gt;}&lt;br /&gt;We passed in “Chapter7” to our constructor because that is what we called our XACT&lt;br /&gt;project. The next thing we need to do is set up our playlist. We can do this inside of our&lt;br /&gt;Initialize method because we added the sound component in our constructor:&lt;br /&gt;string[] playList = { “Song1”, “Song2”, “Song3” };&lt;br /&gt;sound.StartPlayList(playList);&lt;br /&gt;The code tells our sound manager we will be playing three different songs. The library&lt;br /&gt;will keep checking to see if they are playing. If not, it will automatically play the next&lt;br /&gt;one, looping back to the beginning song when it reaches the end of the list.&lt;br /&gt;Now we can actually populate our Update method to check for our input to play all of the&lt;br /&gt;sounds and songs we set up in XACT. We need to add the following code to our Update&lt;br /&gt;method:&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.D1) ||&lt;br /&gt;input.ButtonHandler.WasButtonPressed(0, InputHandler.ButtonType.A))&lt;br /&gt;sound.Play(“gunshot”);&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.D2) ||&lt;br /&gt;input.ButtonHandler.WasButtonPressed(0, InputHandler.ButtonType.B))&lt;br /&gt;sound.Play(“hit”);&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.D3) ||&lt;br /&gt;input.ButtonHandler.WasButtonPressed(0,&lt;br /&gt;InputHandler.ButtonType.LeftShoulder))&lt;br /&gt;sound.Play(“attention”);&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.D4) ||&lt;br /&gt;input.ButtonHandler.WasButtonPressed(0,&lt;br /&gt;InputHandler.ButtonType.LeftStick))&lt;br /&gt;sound.Play(“explosion”);&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.D5) ||&lt;br /&gt;input.ButtonHandler.WasButtonPressed(0,&lt;br /&gt;InputHandler.ButtonType.RightShoulder))&lt;br /&gt;148 CHAPTER 7 Sounds and Music&lt;br /&gt;sound.Play(“bullet”);&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.D6) ||&lt;br /&gt;input.ButtonHandler.WasButtonPressed(0,&lt;br /&gt;InputHandler.ButtonType.RightStick))&lt;br /&gt;sound.Play(“crash”);&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.D7) ||&lt;br /&gt;input.ButtonHandler.WasButtonPressed(0, InputHandler.ButtonType.X))&lt;br /&gt;sound.Play(“complex”);&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.D8) ||&lt;br /&gt;input.ButtonHandler.WasButtonPressed(0, InputHandler.ButtonType.Y))&lt;br /&gt;sound.Toggle(“CoolLoop”);&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.D9) ||&lt;br /&gt;input.ButtonHandler.WasButtonPressed(0,&lt;br /&gt;InputHandler.ButtonType.LeftShoulder))&lt;br /&gt;sound.Toggle(“CoolLoop 2”);&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.P) ||&lt;br /&gt;input.ButtonHandler.WasButtonPressed(0, InputHandler.ButtonType.Start))&lt;br /&gt;{&lt;br /&gt;sound.Toggle(“CoolLoop”);&lt;br /&gt;}&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.S) ||&lt;br /&gt;(input.GamePads[0].Triggers.Right &gt; 0))&lt;br /&gt;sound.StopPlayList();&lt;br /&gt;We are simply checking to see if different keys were pressed or different buttons were&lt;br /&gt;pushed. Based on those results we play different cues that we set up in the XACT project.&lt;br /&gt;A good exercise for us would be to run the demo and reread the section of this chapter&lt;br /&gt;where we set up all of these sounds and see if they do what we expect when we press the&lt;br /&gt;appropriate keys or buttons. In particular we can press the B button or number 2 key&lt;br /&gt;repeatedly and see that the “hit” cue is queuing up as we told it to limit itself to only&lt;br /&gt;playing once and to queue failed requests. We can also click down on our right thumb&lt;br /&gt;stick or press the number 6 key to hear our crash. If the playlist is hindering our hearing&lt;br /&gt;of the sounds we can stop it by pressing the S key or pushing on our right trigger.&lt;br /&gt;The final piece of code for our sound demo is where we can set a global variable for the&lt;br /&gt;RPC we set up as well as the volume of our default category cues. To start, we need to add&lt;br /&gt;two more private member fields:&lt;br /&gt;private float currentVolume = 0.5f;&lt;br /&gt;private float value = 0;&lt;br /&gt;Now we can finish up our Update method with the following code:&lt;br /&gt;if (input.KeyboardState.IsHoldingKey(Keys.Up) ||&lt;br /&gt;input.GamePads[0].DPad.Up == ButtonState.Pressed)&lt;br /&gt;Creating a Sound Demo 149&lt;br /&gt;7&lt;br /&gt;currentVolume += 0.05f;&lt;br /&gt;if (input.KeyboardState.IsHoldingKey(Keys.Down) ||&lt;br /&gt;input.GamePads[0].DPad.Down == ButtonState.Pressed)&lt;br /&gt;currentVolume -= 0.05f;&lt;br /&gt;currentVolume = MathHelper.Clamp(currentVolume, 0.0f, 1.0f);&lt;br /&gt;sound.SetVolume(“Default”, currentVolume);&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.NumPad1))&lt;br /&gt;value = 5000;&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.NumPad2))&lt;br /&gt;value = 25000;&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.NumPad3))&lt;br /&gt;value = 30000;&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.NumPad4))&lt;br /&gt;value = 40000;&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.NumPad5))&lt;br /&gt;value = 50000;&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.NumPad6))&lt;br /&gt;value = 60000;&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.NumPad7))&lt;br /&gt;value = 70000;&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.NumPad8))&lt;br /&gt;value = 80000;&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.NumPad9))&lt;br /&gt;value = 90000;&lt;br /&gt;if (input.KeyboardState.WasKeyPressed(Keys.NumPad0))&lt;br /&gt;value = 100000;&lt;br /&gt;if (input.GamePads[0].Triggers.Left &gt; 0)&lt;br /&gt;value = input.GamePads[0].Triggers.Left * 100000;&lt;br /&gt;sound.SetGlobalVariable(“SpeedOfSound”, value);&lt;br /&gt;This completes our sound demo code and now if we run it and press the Up and Down&lt;br /&gt;arrow keys or on the Dpad we can hear the volume of the sounds associated with our&lt;br /&gt;“Default” category go up and down. We clamp our value between 0 and 1 because that is&lt;br /&gt;what the engine takes to set the volume. This is an example of how checking for the&lt;br /&gt;input state without considering the previous state can get us into trouble. The code will&lt;br /&gt;turn the volume up and down very quickly because it is getting back a true on every call&lt;br /&gt;every frame. Feel free to add Dpad to the updated InputHandler code.&lt;br /&gt;Not only does this code let us test the volume settings, it also lets us set a global variable.&lt;br /&gt;In the XACT project, if we used SpeedOfSound as one of the parameters when setting up&lt;br /&gt;our curve then we can actually modify the way the cue sounds here at runtime. That is&lt;br /&gt;pretty powerful.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-5696697438604990254?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/5696697438604990254/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=5696697438604990254' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/5696697438604990254'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/5696697438604990254'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/creating-sound-demo.html' title='Creating a Sound Demo'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-3441948621959299861</id><published>2008-04-04T21:06:00.001-07:00</published><updated>2008-04-04T21:06:35.487-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='updating'/><category scheme='http://www.blogger.com/atom/ns#' term='update'/><category scheme='http://www.blogger.com/atom/ns#' term='input handler'/><title type='text'>Updating Our Input Handler</title><content type='html'>Before we actually dig into the code to utilize the XACT project we just created, let’s back&lt;br /&gt;up a minute and take another look at our input handler. In particular we want to extend&lt;br /&gt;our keyboard and gamepad functionality. Currently, if we try to trigger any event with a&lt;br /&gt;key press or a button push we will get the event kicked off several times. This is because&lt;br /&gt;for every frame we are checking in our Update method, if a key is pressed for a fraction of&lt;br /&gt;a second the method will return true for many frames. We already know how to solve the&lt;br /&gt;problem because we did it with our Mouse class. We stored the old state and compared it&lt;br /&gt;to the new state to see what has changed. We need to do the same thing here. With the&lt;br /&gt;mouse code, we did it inside of the demo code, but we want this to be done inside of the&lt;br /&gt;library so our game and demo code do not need to worry about the gory details. We will&lt;br /&gt;not be updating the mouse code but that would be an excellent exercise to go through&lt;br /&gt;once we are done with the chapter.&lt;br /&gt;To get started, we need to open up the InputHandler.cs code file inside of our XELibrary&lt;br /&gt;project. The code for our updated InputHandler.cs file is in Listing 7.1. We are not going&lt;br /&gt;to do a deep dive on the code in this chapter (this is devoted to sound after all), but we&lt;br /&gt;are going to quickly examine what has been modified from a distant view.&lt;br /&gt;LISTING 7.1 InputHandler.cs&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using Microsoft.Xna.Framework;&lt;br /&gt;using Microsoft.Xna.Framework.Input;&lt;br /&gt;namespace XELibrary&lt;br /&gt;{&lt;br /&gt;public interface IInputHandler&lt;br /&gt;{&lt;br /&gt;KeyboardHandler KeyboardState { get; }&lt;br /&gt;GamePadState[] GamePads { get; }&lt;br /&gt;ButtonHandler ButtonHandler { get; }&lt;br /&gt;#if !XBOX360&lt;br /&gt;MouseState MouseState { get; }&lt;br /&gt;MouseState PreviousMouseState { get; }&lt;br /&gt;134 CHAPTER 7 Sounds and Music&lt;br /&gt;#endif&lt;br /&gt;};&lt;br /&gt;public partial class InputHandler&lt;br /&gt;: Microsoft.Xna.Framework.GameComponent, IInputHandler&lt;br /&gt;{&lt;br /&gt;public enum ButtonType { A, B, Back, LeftShoulder, LeftStick,&lt;br /&gt;RightShoulder, RightStick, Start, X, Y }&lt;br /&gt;private KeyboardHandler keyboard;&lt;br /&gt;private ButtonHandler gamePadHandler = new ButtonHandler();&lt;br /&gt;private GamePadState[] gamePads = new GamePadState[4];&lt;br /&gt;#if !XBOX360&lt;br /&gt;private MouseState mouseState;&lt;br /&gt;private MouseState prevMouseState;&lt;br /&gt;#endif&lt;br /&gt;public InputHandler(Game game)&lt;br /&gt;: base(game)&lt;br /&gt;{&lt;br /&gt;// TODO: Construct any child components here&lt;br /&gt;game.Services.AddService(typeof(IInputHandler), this);&lt;br /&gt;//initialize our member fields&lt;br /&gt;keyboard = new KeyboardHandler();&lt;br /&gt;gamePads[0] = GamePad.GetState(PlayerIndex.One);&lt;br /&gt;gamePads[1] = GamePad.GetState(PlayerIndex.Two);&lt;br /&gt;gamePads[2] = GamePad.GetState(PlayerIndex.Three);&lt;br /&gt;gamePads[3] = GamePad.GetState(PlayerIndex.Four);&lt;br /&gt;#if !XBOX360&lt;br /&gt;Game.IsMouseVisible = true;&lt;br /&gt;prevMouseState = Mouse.GetState();&lt;br /&gt;#endif&lt;br /&gt;}&lt;br /&gt;public override void Initialize()&lt;br /&gt;{&lt;br /&gt;base.Initialize();&lt;br /&gt;}&lt;br /&gt;public override void Update(GameTime gameTime)&lt;br /&gt;{&lt;br /&gt;Updating Our Input Handler 135&lt;br /&gt;7&lt;br /&gt;LISTING 7.1 Continued&lt;br /&gt;keyboard.Update();&lt;br /&gt;gamePadHandler.Update();&lt;br /&gt;if (keyboard.IsKeyDown(Keys.Escape))&lt;br /&gt;Game.Exit();&lt;br /&gt;if (gamePadHandler.WasButtonPressed(0, ButtonType.Back))&lt;br /&gt;Game.Exit();&lt;br /&gt;#if !XBOX360&lt;br /&gt;//Set our previous state&lt;br /&gt;prevMouseState = mouseState;&lt;br /&gt;//Get our new state&lt;br /&gt;mouseState = Mouse.GetState();&lt;br /&gt;#endif&lt;br /&gt;base.Update(gameTime);&lt;br /&gt;}&lt;br /&gt;#region IInputHandler Members&lt;br /&gt;public KeyboardHandler KeyboardState&lt;br /&gt;{&lt;br /&gt;get { return (keyboard); }&lt;br /&gt;}&lt;br /&gt;public ButtonHandler ButtonHandler&lt;br /&gt;{&lt;br /&gt;get { return (gamePadHandler); }&lt;br /&gt;}&lt;br /&gt;public GamePadState[] GamePads&lt;br /&gt;{&lt;br /&gt;get { return(gamePads); }&lt;br /&gt;}&lt;br /&gt;#if !XBOX360&lt;br /&gt;public MouseState MouseState&lt;br /&gt;{&lt;br /&gt;get { return(mouseState); }&lt;br /&gt;}&lt;br /&gt;public MouseState PreviousMouseState&lt;br /&gt;{&lt;br /&gt;136 CHAPTER 7 Sounds and Music&lt;br /&gt;LISTING 7.1 Continued&lt;br /&gt;get { return(prevMouseState); }&lt;br /&gt;}&lt;br /&gt;#endif&lt;br /&gt;#endregion&lt;br /&gt;}&lt;br /&gt;public class ButtonHandler&lt;br /&gt;{&lt;br /&gt;private GamePadState[] prevGamePadsState = new GamePadState[4];&lt;br /&gt;private GamePadState[] gamePadsState = new GamePadState[4];&lt;br /&gt;public ButtonHandler()&lt;br /&gt;{&lt;br /&gt;prevGamePadsState[0] = GamePad.GetState(PlayerIndex.One);&lt;br /&gt;prevGamePadsState[1] = GamePad.GetState(PlayerIndex.Two);&lt;br /&gt;prevGamePadsState[2] = GamePad.GetState(PlayerIndex.Three);&lt;br /&gt;prevGamePadsState[3] = GamePad.GetState(PlayerIndex.Four);&lt;br /&gt;}&lt;br /&gt;public void Update()&lt;br /&gt;{&lt;br /&gt;//set our previous state to our new state&lt;br /&gt;prevGamePadsState[0] = gamePadsState[0];&lt;br /&gt;prevGamePadsState[1] = gamePadsState[1];&lt;br /&gt;prevGamePadsState[2] = gamePadsState[2];&lt;br /&gt;prevGamePadsState[3] = gamePadsState[3];&lt;br /&gt;//get our new state&lt;br /&gt;//gamePadsState = GamePad.State .GetState();&lt;br /&gt;gamePadsState[0] = GamePad.GetState(PlayerIndex.One);&lt;br /&gt;gamePadsState[1] = GamePad.GetState(PlayerIndex.Two);&lt;br /&gt;gamePadsState[2] = GamePad.GetState(PlayerIndex.Three);&lt;br /&gt;gamePadsState[3] = GamePad.GetState(PlayerIndex.Four);&lt;br /&gt;}&lt;br /&gt;public bool WasButtonPressed(int playerIndex,&lt;br /&gt;InputHandler.ButtonType button)&lt;br /&gt;{&lt;br /&gt;int pi = playerIndex;&lt;br /&gt;switch(button)&lt;br /&gt;{ //start switch&lt;br /&gt;case InputHandler.ButtonType.A:&lt;br /&gt;{&lt;br /&gt;return(gamePadsState[pi].Buttons.A == ButtonState.Pressed &amp;&amp;&lt;br /&gt;Updating Our Input Handler 137&lt;br /&gt;7&lt;br /&gt;LISTING 7.1 Continued&lt;br /&gt;prevGamePadsState[pi].Buttons.A == ButtonState.Released);&lt;br /&gt;}&lt;br /&gt;case InputHandler.ButtonType.B:&lt;br /&gt;{&lt;br /&gt;return(gamePadsState[pi].Buttons.B == ButtonState.Pressed &amp;&amp;&lt;br /&gt;prevGamePadsState[pi].Buttons.B == ButtonState.Released);&lt;br /&gt;}&lt;br /&gt;case InputHandler.ButtonType.Back:&lt;br /&gt;{&lt;br /&gt;return(gamePadsState[pi].Buttons.Back == ButtonState.Pressed &amp;&amp;&lt;br /&gt;prevGamePadsState[pi].Buttons.Back == ButtonState.Released);&lt;br /&gt;}&lt;br /&gt;case InputHandler.ButtonType.LeftShoulder:&lt;br /&gt;{&lt;br /&gt;return(gamePadsState[pi].Buttons.LeftShoulder ==&lt;br /&gt;ButtonState.Pressed &amp;&amp;&lt;br /&gt;prevGamePadsState[pi].Buttons.LeftShoulder ==&lt;br /&gt;ButtonState.Released);&lt;br /&gt;}&lt;br /&gt;case InputHandler.ButtonType.LeftStick:&lt;br /&gt;{&lt;br /&gt;return(gamePadsState[pi].Buttons.LeftStick ==&lt;br /&gt;ButtonState.Pressed &amp;&amp;&lt;br /&gt;prevGamePadsState[pi].Buttons.LeftStick ==&lt;br /&gt;ButtonState.Released);&lt;br /&gt;}&lt;br /&gt;case InputHandler.ButtonType.RightShoulder:&lt;br /&gt;{&lt;br /&gt;return(gamePadsState[pi].Buttons.RightShoulder ==&lt;br /&gt;ButtonState.Pressed &amp;&amp;&lt;br /&gt;prevGamePadsState[pi].Buttons.RightShoulder ==&lt;br /&gt;ButtonState.Released);&lt;br /&gt;}&lt;br /&gt;case InputHandler.ButtonType.RightStick:&lt;br /&gt;{&lt;br /&gt;return(gamePadsState[pi].Buttons.RightStick ==&lt;br /&gt;ButtonState.Pressed &amp;&amp;&lt;br /&gt;prevGamePadsState[pi].Buttons.RightStick ==&lt;br /&gt;ButtonState.Released);&lt;br /&gt;}&lt;br /&gt;case InputHandler.ButtonType.Start:&lt;br /&gt;{&lt;br /&gt;return(gamePadsState[pi].Buttons.Start ==&lt;br /&gt;ButtonState.Pressed &amp;&amp;&lt;br /&gt;138 CHAPTER 7 Sounds and Music&lt;br /&gt;LISTING 7.1 Continued&lt;br /&gt;prevGamePadsState[pi].Buttons.Start ==&lt;br /&gt;ButtonState.Released);&lt;br /&gt;}&lt;br /&gt;case InputHandler.ButtonType.X:&lt;br /&gt;{&lt;br /&gt;return(gamePadsState[pi].Buttons.X == ButtonState.Pressed &amp;&amp;&lt;br /&gt;prevGamePadsState[pi].Buttons.X == ButtonState.Released);&lt;br /&gt;}&lt;br /&gt;case InputHandler.ButtonType.Y:&lt;br /&gt;{&lt;br /&gt;return(gamePadsState[pi].Buttons.Y == ButtonState.Pressed &amp;&amp;&lt;br /&gt;prevGamePadsState[pi].Buttons.Y == ButtonState.Released);&lt;br /&gt;}&lt;br /&gt;default:&lt;br /&gt;throw (new ArgumentException());&lt;br /&gt;} //end switch&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;public class KeyboardHandler&lt;br /&gt;{&lt;br /&gt;private KeyboardState prevKeyboardState;&lt;br /&gt;private KeyboardState keyboardState;&lt;br /&gt;public KeyboardHandler()&lt;br /&gt;{&lt;br /&gt;prevKeyboardState = Keyboard.GetState();&lt;br /&gt;}&lt;br /&gt;public bool IsKeyDown(Keys key)&lt;br /&gt;{&lt;br /&gt;return (keyboardState.IsKeyDown(key));&lt;br /&gt;}&lt;br /&gt;public bool IsHoldingKey(Keys key)&lt;br /&gt;{&lt;br /&gt;return(keyboardState.IsKeyDown(key) &amp;&amp;&lt;br /&gt;prevKeyboardState.IsKeyDown(key));&lt;br /&gt;}&lt;br /&gt;public bool WasKeyPressed(Keys key)&lt;br /&gt;{&lt;br /&gt;return(keyboardState.IsKeyDown(key) &amp;&amp;&lt;br /&gt;prevKeyboardState.IsKeyUp(key));&lt;br /&gt;Updating Our Input Handler 139&lt;br /&gt;7&lt;br /&gt;LISTING 7.1 Continued&lt;br /&gt;}&lt;br /&gt;public bool HasReleasedKey(Keys key)&lt;br /&gt;{&lt;br /&gt;return(keyboardState.IsKeyUp(key) &amp;&amp;&lt;br /&gt;prevKeyboardState.IsKeyDown(key));&lt;br /&gt;}&lt;br /&gt;public void Update()&lt;br /&gt;{&lt;br /&gt;//set our previous state to our new state&lt;br /&gt;prevKeyboardState = keyboardState;&lt;br /&gt;//get our new state&lt;br /&gt;keyboardState = Keyboard.GetState();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;The first thing to notice is that we added two more classes at the end of our file:&lt;br /&gt;KeyboardHandler and ButtonHandler. These objects each have an Update method that&lt;br /&gt;gets called by our main Update method inside of InputHandler. The Update method stores&lt;br /&gt;the previous state and resets the new state. This is the key to it all. We simply check our&lt;br /&gt;new state against our old state to see if keys or buttons have been pressed or released. We&lt;br /&gt;have helper functions that our game code can call to check if the key was pressed or a&lt;br /&gt;button was pressed. These helper functions just query the previous and new states of the&lt;br /&gt;appropriate input device and return a boolean value. With this implemented we do not&lt;br /&gt;run into the issue of getting multiple events kicked off because the gamer is holding the&lt;br /&gt;button down. It also gives us a base from which to start working. We left our most current&lt;br /&gt;state available, as we still need that for our triggers and Dpad. Dpad could also be put into&lt;br /&gt;this handler because it is treated as a button, but that along with wrapping up the mouse&lt;br /&gt;information is not in the code. This should be a good starting point if either of those is&lt;br /&gt;needed, though.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-3441948621959299861?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/3441948621959299861/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=3441948621959299861' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/3441948621959299861'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/3441948621959299861'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/updating-our-input-handler.html' title='Updating Our Input Handler'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-6519828737339850019</id><published>2008-04-04T21:05:00.003-07:00</published><updated>2008-04-04T21:05:58.952-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sound'/><category scheme='http://www.blogger.com/atom/ns#' term='music'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>Sounds and Music</title><content type='html'>Stop and think for a moment what your favorite game&lt;br /&gt;would be like if it did not have sound. Music sets the&lt;br /&gt;atmosphere for our games and sound effects adds to the&lt;br /&gt;realism of our games. In this chapter we discuss how to get&lt;br /&gt;music and sounds into our demos and games.&lt;br /&gt;To do this we will need to use the Microsoft Cross-Platform&lt;br /&gt;Audio Creation Tool (XACT), which Microsoft provides for&lt;br /&gt;us. The tool can be found in our Programs/Microsoft XNA&lt;br /&gt;Game Studio Express/Tools menu. Once we have the tool&lt;br /&gt;opened we will create wave banks and sound banks and&lt;br /&gt;discuss global settings. We will then actually create a sound&lt;br /&gt;manager that we can add to our library&lt;br /&gt;&lt;br /&gt;Microsoft Cross-Platform Audio&lt;br /&gt;Creation Tool (XACT)&lt;br /&gt;&lt;br /&gt;Unlike textures and 3D models, we do not simply put our&lt;br /&gt;raw wave files into the Content Pipeline directly. Instead&lt;br /&gt;we use XACT to bundle them together and add effects to&lt;br /&gt;the different sounds. The XACT tool allows us to associate&lt;br /&gt;categories with our sounds. When we set a sound to have a&lt;br /&gt;category of Music, it allows the Xbox 360 to ignore the&lt;br /&gt;music if the gamer has a playlist playing on his or her&lt;br /&gt;Xbox 360.&lt;br /&gt;Before we open the actual tool we need to open up the&lt;br /&gt;XACT Auditioning Utility, which is found in the same location&lt;br /&gt;as XACT itself. We only need to do this if we actually&lt;br /&gt;want to audition (listen to) the sounds we are making&lt;br /&gt;inside of XACT. This can, of course, be beneficial, especially&lt;br /&gt;when we want to add effects to the file. With that said,&lt;br /&gt;XACT is not a sound editing software package. It takes&lt;br /&gt;completed wave files and puts them in a format that XNA&lt;br /&gt;can read and use. We can do simple effects like change the&lt;br /&gt;124 CHAPTER 7 Sounds and Music&lt;br /&gt;pitch and volume but the tool is not designed to be a wave file editor.&lt;br /&gt;We first need to hook our XACT tool up to the Auditioning Utility we launched before.&lt;br /&gt;The Auditioning Utility must be run before the XACT tool is run. To play our sounds we&lt;br /&gt;need to tell XACT to connect to the Auditioning Utility by clicking the Audition menu&lt;br /&gt;item and then clicking the Connect To (machine) item. After we have successfully&lt;br /&gt;connected, the Auditioning Utility will say “XACT tool is now connected….”&lt;br /&gt;When we open the tool we will see an empty project to which we can add .wav files.&lt;br /&gt;After adding the files we can then set them up as sounds and create cue names for them&lt;br /&gt;that we can kick off inside of our code. We can modify properties to get different effects&lt;br /&gt;from the sounds.&lt;br /&gt;Wave Banks&lt;br /&gt;To get started we can create a new wave bank from inside XACT. To create a wave bank,&lt;br /&gt;we can follow these steps:&lt;br /&gt;1. Right-click Wave Banks and select New Wave Bank. This can be seen in Figure 7.1.&lt;br /&gt;2. Inside of the Wave Bank empty pane, right-click and select Insert Wave File(s).&lt;br /&gt;3. Find a wave file from the Spacewar project. We can use the Theme.wav file from&lt;br /&gt;MySpacewarWin1\Content\Audio\Waves\Music.&lt;br /&gt;FIGURE 7.1 The XACT tool allows us to add wave banks to utilize the sounds in our games.&lt;br /&gt;4. Because we have our Auditioning Tool set up and XACT connected to it, we can&lt;br /&gt;simply select the wave file and press the spacebar to hear it play. We could also&lt;br /&gt;right-click and select Play, or click Play in the toolbar. As with most graphical user&lt;br /&gt;interfaces (GUIs) there are many ways to accomplish the same task. This book only&lt;br /&gt;lists one way in most cases.&lt;br /&gt;We can go ahead and add in a few other wave files as well. Let’s follow the preceding&lt;br /&gt;steps to enter all of the collision wave files from Spacewar. We can open them all up at&lt;br /&gt;one time in the Open dialog box.&lt;br /&gt;Sound Banks&lt;br /&gt;Even though we have the wave file loaded inside our XACT project, we still could not use&lt;br /&gt;it in our game. We have to create a sound bank first. To create a sound bank we can&lt;br /&gt;follow these steps:&lt;br /&gt;1. Right-click Sound Banks and select New Sound Bank. Just like the wave bank, we&lt;br /&gt;could also accomplish this through the toolbar or the main menu items.&lt;br /&gt;2. Our work pane just filled up with our Sound Bank window. We will need to work&lt;br /&gt;with the Wave Bank window as well as the Sound Bank window so we will want to&lt;br /&gt;position them so we can see them both. One way to do this is to click Tile&lt;br /&gt;Horizontally inside of the Window menu item.&lt;br /&gt;3. Now that we can see both windows we need to drag our wave file from the wave&lt;br /&gt;bank into the sound bank, inside the top left pane (sounds frame).&lt;br /&gt;4. A cue for the sound needs to be created in order for our code to utilize it. We can&lt;br /&gt;create a cue by dragging the sound from the top left pane (sounds frame) into the&lt;br /&gt;bottom left pane (cues frame).&lt;br /&gt;This is the bare minimum we need to do to play sounds in our games. To hear the sound&lt;br /&gt;we can select it and press the spacebar. We can press Escape to stop the sound. To get&lt;br /&gt;sound effects and music into our games, these steps will work. In the next sections we&lt;br /&gt;discuss more advanced ways to manipulate our sounds to get them ready for our game.&lt;br /&gt;Understanding Variations&lt;br /&gt;To accomplish something more than just playing sounds we need to understand variations.&lt;br /&gt;With variations we can assign many waves to a track and we can create different&lt;br /&gt;events for those tracks to create a sound. We can assign many sounds to a cue. We can&lt;br /&gt;then set up how those sounds or waves are to be played. We will be utilizing XACT to&lt;br /&gt;create different variations and then we are going to write a library component that a&lt;br /&gt;demo can use to play these cues.&lt;br /&gt;We can close out our existing XACT instance and open up a new one. We need to create a&lt;br /&gt;wave bank and a sound bank to put our waves in. On this book’s CD, under this chapter’s&lt;br /&gt;folder there is a subfolder entitled Sounds. We need to add all of these waves into our&lt;br /&gt;Understanding Variations 125&lt;br /&gt;7&lt;br /&gt;wave bank. After adding in the waves we need to create some sounds. We are going to&lt;br /&gt;add the different sounds and create different variations so we can learn how to use some&lt;br /&gt;of the XACT features by example.&lt;br /&gt;1. We can drag the Attention and Explosion sounds directly into our cues frame&lt;br /&gt;(bottom left pane) because we are going to play these sounds as is.&lt;br /&gt;2. We can drag the Axe_throw sound directly into our cues frame and rename the cue&lt;br /&gt;to Bullet. We can do this by right-clicking the name in the cues frame and selecting&lt;br /&gt;Rename. At this point, the screen should resemble Figure 7.2.&lt;br /&gt;126 CHAPTER 7 Sounds and Music&lt;br /&gt;FIGURE 7.2 Wave files can be dragged directly into the cues frame.&lt;br /&gt;3. To start our more complicated tasks let’s drag our CoolLoop wave into our cues&lt;br /&gt;frame.&lt;br /&gt;4. In the top right pane (tracks frame) we can see that XACT created a track with a&lt;br /&gt;play event that include our wave name. We want to make sure this sound loops so&lt;br /&gt;we click the Play Wave tree node of the Track 1 root to select it.&lt;br /&gt;5. In the properties window we can see LoopEvent under the PlayWave Properties. The&lt;br /&gt;default value is No but we could either loop it a certain number of times by selecting&lt;br /&gt;Finite and then entering the number of times to loop in the LoopCount property&lt;br /&gt;or we can have it loop forever by selecting Infinite. We are going to let this&lt;br /&gt;sound loop forever so we select Infinite. We can see this in Figure 7.3.&lt;br /&gt;FIGURE 7.3 We can set our play event on a track to loop indefinitely.&lt;br /&gt;6. Because this loop is going to be music we can click the CoolLoop’s sound icon and&lt;br /&gt;drag it on top of the Music category on the left side of the window. When this is&lt;br /&gt;successful we will see the Category change from Default to Music.&lt;br /&gt;7. Next up we are going to add multiple sounds into one cue. We will use&lt;br /&gt;Synth_beep_1 to start us off. Let’s drag that wave into our cues frame.&lt;br /&gt;8. Now we want to make sure that the sound name is selected (in our sounds frame) so&lt;br /&gt;the track frame is showing the play event for track 1.&lt;br /&gt;9. We need to drag Synth_beep_2 and Synth_beep_3 waves and drop them on our play&lt;br /&gt;event inside of track 1. We need to be careful to not drag over the cues frame as it&lt;br /&gt;will make the tracks frame empty (it deselects the sound from the sound pane). We&lt;br /&gt;drag the files by clicking on the icon (XACT does not allow us to drag by the name&lt;br /&gt;of the wave). We can see where we need to release the cursor in Figure 7.4. The final&lt;br /&gt;result after releasing the cursor and completing our drop operation can be seen in&lt;br /&gt;Figure 7.5.&lt;br /&gt;10. Rename this cue from Synth_beep_1 to Hit.&lt;br /&gt;11. With Hit as our active cue, we can press the spacebar to hear it play (assuming we&lt;br /&gt;are connected to the Auditioning Utility). Let’s hit the spacebar several times in a&lt;br /&gt;row very fast. We can hear one sound being played every time we hit the spacebar&lt;br /&gt;regardless if the previous sound was played. We see they are not played at the same&lt;br /&gt;time by “pressing play” once. By putting our different waves directly into a play&lt;br /&gt;event we are giving XACT a list of waves to play from when we call play. It does not&lt;br /&gt;play them all at once (but we will see how to do that in a moment).&lt;br /&gt;Understanding Variations 127&lt;br /&gt;7&lt;br /&gt;12. Because we do not want this particular cue to play more than one sound at a time&lt;br /&gt;we can change the LimitInstances property in the Instance Limiting Properties&lt;br /&gt;section of our properties window to True. We will need to have our cue name&lt;br /&gt;selected to do this. Now when we press the spacebar multiple times it will not start&lt;br /&gt;playing until the last sound has finished.&lt;br /&gt;13. We can hear the sounds are random but we want them to play in the order we specified&lt;br /&gt;in the play event of our track. To do this we need to select Ordered in the&lt;br /&gt;PlayListType property in the Variation Playlist Properties section of the property&lt;br /&gt;frame. We need to do this when we have the cue selected. Changing this value to&lt;br /&gt;Ordered causes XACT to play the sounds in the order we specified. If we wanted it&lt;br /&gt;to start with a random entry and then do them in order, we could have selected&lt;br /&gt;Ordered From Random.&lt;br /&gt;14. Now when we play the sounds, they play in order and only play one at a time.&lt;br /&gt;However, we want the sounds to be queued up so that if we press the spacebar five&lt;br /&gt;times, it will play all of the waves in the sound with each one starting as soon as the&lt;br /&gt;previous one finishes. To do this we need to change the BehaviorAtMax property to&lt;br /&gt;Queue instead of FailToPlay. This can be useful for queuing up things like voiceover&lt;br /&gt;audio that we would never want to play simultaneously. This is shown in Figure 7.6.&lt;br /&gt;Understanding Variations 129&lt;br /&gt;7&lt;br /&gt;15. Now we are going to make a crash cue. To start, let’s drag Ambulance_siren from our&lt;br /&gt;waves into our cues and rename the cue to Crash.&lt;br /&gt;16. Inside of our tracks frame, with our Ambulance_siren sound selected from the sound&lt;br /&gt;frame, right-click and add a new track.&lt;br /&gt;17. Now we can add a play event to the track we just added by right-clicking the track&lt;br /&gt;and selecting Add Event &gt; Play Wave.&lt;br /&gt;18. We need to drag the Car_brake wave into the play event of the track we just created.&lt;br /&gt;Remember not to drag across the cue frame, as the contents of the track frame will&lt;br /&gt;disappear.&lt;br /&gt;19. We need to repeat steps 16 through 18 with the wave files Bus_horn and Explosion.&lt;br /&gt;When this step is completed we should have a total of four tracks, each with its&lt;br /&gt;own play event that has a wave file associated with it. We have expanded the Sound&lt;br /&gt;Banks window in Figure 7.7 so we can see the end result.&lt;br /&gt;130 CHAPTER 7 Sounds and Music&lt;br /&gt;FIGURE 7.7 We can create multiple tracks for a sound, each with one or more events in our&lt;br /&gt;tracks frame.&lt;br /&gt;20. Now if we play our Crash cue we will hear all four sounds at the same time. We&lt;br /&gt;want them to be spaced out as to simulate an accident. We can delay the time at&lt;br /&gt;which different tracks start to play by setting the TimeStamp property in the Timing&lt;br /&gt;Properties section of our property frame when we have the play wave event selected.&lt;br /&gt;Our Car_brake wave can be left alone as it is a little longer of a sound file. We&lt;br /&gt;should modify the rest of the values as follows:&lt;br /&gt;Bus_horn: 0.300&lt;br /&gt;Explosion: 1.000&lt;br /&gt;Ambulance_siren: 1.600&lt;br /&gt;Now when we play the cue we can hear something that resembles a car colliding&lt;br /&gt;with a bus, creating a large explosion and the fastest EMT response time ever!&lt;br /&gt;21. Now we want to make a variant of our explosion sound. We are going to make a&lt;br /&gt;gunshot sound without requiring an additional wave file to be used. To do this we&lt;br /&gt;are going to drag our Explosion sound (top right pane) into the empty white space&lt;br /&gt;inside of the same sound pane so it will create a copy of itself. It should have called&lt;br /&gt;itself Explosion 2. Let’s drag that Explosion 2 from the sounds frame into our cues&lt;br /&gt;frame and rename the cue to Gunshot.&lt;br /&gt;22. When we play Gunshot, it does not sound any different than Explosion. Let’s&lt;br /&gt;change that by adding a Pitch event to our only track for the Explosion 2 sound in&lt;br /&gt;our tracks frame. We add this event just like we added the play event earlier, by&lt;br /&gt;right-clicking the track and selecting Add Event &gt; Pitch.&lt;br /&gt;23. Now we need to actually modify the pitch to get the desired sound effect. To do this&lt;br /&gt;we need to make sure our Pitch event is selected and then change the Constant&lt;br /&gt;value. We can find this value in our properties frame under Pitch Properties/Setting&lt;br /&gt;Type (Equation)/EquationType (Constant). Let’s change the pitch to 50.00 as shown&lt;br /&gt;in Figure 7.8. Now if we play the cue we will hear something that resembles a&lt;br /&gt;gunshot instead of an explosion. We did not have to add another large wave file to&lt;br /&gt;accomplish this effect.&lt;br /&gt;Understanding Variations 131&lt;br /&gt;7&lt;br /&gt;24. Next, we are going to create a cue with multiple sounds. We need to right-click&lt;br /&gt;inside of our cues frame and select New Cue. We can name this cue Complex.&lt;br /&gt;25. Drag the Explosion sound down on top of the Complex cue. Let’s do the same thing&lt;br /&gt;with the Synth_beep_1 sound. Remember, this Synth_beep_1 sound has its own&lt;br /&gt;sound variations already as it plays three different waves in order.&lt;br /&gt;26. We need to change the PlayList type for this Complex cue to Random. This way it&lt;br /&gt;will just play a sound randomly even if the one it picks was just played.&lt;br /&gt;27. The final thing we will do is add a music playlist. Unfortunately, XACT does not&lt;br /&gt;have a way to give us typical playlist functionality so we will have to put that into&lt;br /&gt;our code. For now, though, we can at least add our songs to this playlist. We will&lt;br /&gt;start by dragging our Song1, Song2, and Song3 waves into our sounds frame.&lt;br /&gt;28. We will also drag those sounds to our music category.&lt;br /&gt;29. Now we need to drag our Song1, Song2, and Song3 sounds from our sounds frame&lt;br /&gt;into the cues frame.&lt;br /&gt;30. We can now save our project, calling it Chapter7.&lt;br /&gt;That was a lot of examples, but it was worth going through because at this point we have&lt;br /&gt;good idea of how to do a lot of sound manipulation to prepare cues for our games. Our&lt;br /&gt;games will always reference the cue value.&lt;br /&gt;There are other actions XACT allows us to do, such as setting local and global variables,&lt;br /&gt;setting up transitions through interactive audio settings, and setting up runtime parameter&lt;br /&gt;controls (RPCs).&lt;br /&gt;We can create RPCs when a simple pitch or volume change across the board will not do.&lt;br /&gt;Perhaps we would like to add some reverb, or maybe we would like to modify the volume&lt;br /&gt;as a cue plays up and down. Doing any of these things requires setting up an RPC, which&lt;br /&gt;can be done by right-clicking the RPC tree node and selecting New RPC Preset as shown&lt;br /&gt;in Figure 7.9.&lt;br /&gt;Then we can drag that preset over to one of our sounds in the sounds frame. To test with,&lt;br /&gt;we can make a copy of our CoolLoop sound and then add our preset to this new sound&lt;br /&gt;by dragging the RPC on top of the new sound we just created. We can open the RPC&lt;br /&gt;preset by double-clicking it. Because there is only one sound it is associated with, it will&lt;br /&gt;play that one. At the top of the RPC dialog box we can select other sounds (if we have&lt;br /&gt;added the RPC to multiple sounds). A default volume curve has been added for us. We&lt;br /&gt;can move the points around and then the vertical horizontal bar that is the same color as&lt;br /&gt;our curve can be moved left and right. The bar can be moved or we can modify the variable&lt;br /&gt;above beside the curve declaration. This is the variable that we can change in our&lt;br /&gt;code to cause the sound to react exactly how we want. We might want to do this, for&lt;br /&gt;example, to dim the background music when dialogue is happening between characters.&lt;br /&gt;We can pass a value to the global variable that will produce the sound identical to what&lt;br /&gt;we are hearing as we audition the sound with our RPC added. We can add more curves&lt;br /&gt;(pitch and reverb) by right-clicking the Volume item at the top of the dialog box and&lt;br /&gt;selecting Add New Curve. We can add nodes to our curve by right-clicking inside of the&lt;br /&gt;main white area and selecting Add. A screen shot of this dialog box is shown in Figure&lt;br /&gt;7.10. Have fun coming up with a totally different CoolLoop 2 sound!&lt;br /&gt;7&lt;br /&gt;We can pause and resume all sounds in a category. This means that we could organize our&lt;br /&gt;sounds in such a way that sounds that are used in our playing state can all be assigned to&lt;br /&gt;a category we can define. Then through the code we can pause that category and it will&lt;br /&gt;pause all sounds that are playing. This way we do not need to worry ourselves with&lt;br /&gt;making sure all the sounds stop when someone pauses the game. When we associate a&lt;br /&gt;sound with the Music category the Xbox 360 can mute that and replace it with the&lt;br /&gt;playlist the gamer has his or her console playing at the time. This is a really nice feature&lt;br /&gt;because no matter how good our soundtrack is, at some point gamers will most likely&lt;br /&gt;want to play our games with their own music in the background.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-6519828737339850019?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/6519828737339850019/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=6519828737339850019' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/6519828737339850019'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/6519828737339850019'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/sounds-and-music.html' title='Sounds and Music'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-7550168431475126406</id><published>2008-04-04T21:05:00.001-07:00</published><updated>2008-04-04T21:05:32.575-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='texture'/><category scheme='http://www.blogger.com/atom/ns#' term='texturing'/><category scheme='http://www.blogger.com/atom/ns#' term='3d'/><category scheme='http://www.blogger.com/atom/ns#' term='model'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>Texturing 3D Models</title><content type='html'>Now, let’s replace that texture with one we will load on the fly. We could just modify our&lt;br /&gt;texture resource if we wanted to, but let’s assume that we want to keep that intact and as&lt;br /&gt;we load different asteroids we want some to use that brownish texture and some to use&lt;br /&gt;our newly created texture, on which we will simply remove the color. So let’s fire up our&lt;br /&gt;favorite paint program and open up the .tga file and turn it into a grayscale image. If&lt;br /&gt;needed, the image asteroid1-grey.tga can be taken from the CD in this chapter’s source&lt;br /&gt;code. Let’s add our newly created image into our Solution Explorer (or we can just include&lt;br /&gt;it into our project if we saved the new version in our /Textures/ subfolder from our paint&lt;br /&gt;program).&lt;br /&gt;Add the following code in our LoadGraphicsContent method:&lt;br /&gt;originalAsteroid = content.Load&lt;Texture2D&gt;(@”Content\Textures\asteroid1“);&lt;br /&gt;greyAsteroid = content.Load&lt;Texture2D&gt;(@”Content\Textures\asteroid1-grey”);&lt;br /&gt;Just like adding our model, we can add our texture asset very easily. Of course, now we&lt;br /&gt;have to actually declare our private member field:&lt;br /&gt;private Texture2D originalAsteroid;&lt;br /&gt;private Texture2D greyAsteroid;&lt;br /&gt;Now we can make a couple of changes to our DrawModel method. We need to add in&lt;br /&gt;another parameter of type Texture2D and call it texture. We also need to actually set our&lt;br /&gt;effect to use that texture if it was passed in, which can be seen in the following code:&lt;br /&gt;if (texture != null)&lt;br /&gt;be.Texture = texture;&lt;br /&gt;This code statement is inside of the inner foreach loop with the rest of the code that sets&lt;br /&gt;the properties of our basic effect that is being used by our model. We are simply checking&lt;br /&gt;to see if null is passed in; if not, we are setting the texture of the effect. As we saw earlier,&lt;br /&gt;the effect is getting applied to the mesh of our model, so we only need to modify our call&lt;br /&gt;to our DrawModel to pass in the new texture. We will go ahead and just create another&lt;br /&gt;asteroid on our screen by replacing our current drawing code with the following:&lt;br /&gt;world = Matrix.CreateTranslation(new Vector3(0, 0, -4000));&lt;br /&gt;DrawModel(ref model, ref world, greyAsteroid);&lt;br /&gt;world = Matrix.CreateTranslation(new Vector3(0, 0, 4000));&lt;br /&gt;DrawModel(ref model, ref world, originalAsteroid);&lt;br /&gt;The first line did not change, but it is added here for readability purposes. The second&lt;br /&gt;statement we are actually passing in is our new texture. The last two statements are&lt;br /&gt;placing another asteroid behind us and resetting the texture to the original one. We can&lt;br /&gt;run this program and spin our camera to see both asteroids being drawn.&lt;br /&gt;120 CHAPTER 6 Loading and Texturing 3D Objects&lt;br /&gt;Now, let’s apply some transformations to our asteroids. We can add some rotation to get&lt;br /&gt;them to do a little more than they are right now. To do this, we just need to replace our&lt;br /&gt;Draw code with the following:&lt;br /&gt;world = Matrix.CreateRotationY(MathHelper.ToRadians(&lt;br /&gt;270.0f * (float)gameTime.TotalGameTime.TotalSeconds)) *&lt;br /&gt;Matrix.CreateTranslation(new Vector3(0, 0, -4000));&lt;br /&gt;DrawModel(ref model, ref world, greyAsteroid);&lt;br /&gt;world = Matrix.CreateRotationY(MathHelper.ToRadians(&lt;br /&gt;45.0f * (float)gameTime.TotalGameTime.TotalSeconds)) *&lt;br /&gt;Matrix.CreateRotationZ(MathHelper.ToRadians(&lt;br /&gt;45.0f * (float)gameTime.TotalGameTime.TotalSeconds)) *&lt;br /&gt;Matrix.CreateTranslation(new Vector3(0, 0, 4000));&lt;br /&gt;DrawModel(ref model, ref world, originalAsteroid);&lt;br /&gt;Even with the code broken to fit on the page, we can still see that we only have four&lt;br /&gt;statements, just like before. The only two that changed are our code that modified the&lt;br /&gt;world matrix. This makes sense because we want to rotate our asteroids. We start by&lt;br /&gt;looking at our first world transformation and can see that we are simply rotating it&lt;br /&gt;around the y axis by 270 degrees * the number of seconds our game has been running.&lt;br /&gt;This effectively makes it continuously render every frame. After rotating we still translate&lt;br /&gt;it like we did before, moving it 4,000 units into our world. The second world transformation&lt;br /&gt;is similar except we are only rotating by 45 degrees instead of 270 degrees. We are&lt;br /&gt;also rotating around the x axis by the same amount. This should give us a decent wobble&lt;br /&gt;effect. Finally we are translating 4,000 units behind us just like before. We can compile&lt;br /&gt;and run our program and see our asteroids are moving (well, rotating in place).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-7550168431475126406?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/7550168431475126406/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=7550168431475126406' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/7550168431475126406'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/7550168431475126406'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/texturing-3d-models.html' title='Texturing 3D Models'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-7126532246450793186</id><published>2008-04-04T21:04:00.002-07:00</published><updated>2008-04-04T21:05:07.930-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='3d'/><category scheme='http://www.blogger.com/atom/ns#' term='loading'/><category scheme='http://www.blogger.com/atom/ns#' term='model'/><category scheme='http://www.blogger.com/atom/ns#' term='load'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>Loading 3D Models</title><content type='html'>The XNA Framework’s Content Pipeline handles loading .X and .FBX files automatically&lt;br /&gt;when they are pasted into the Solution Explorer (or included in the project). This is when&lt;br /&gt;the Content Pipeline goes through the process described in the previous section of&lt;br /&gt;importing, processing, and compiling the data. We then can use our game class and the&lt;br /&gt;Content Manager to read the model information.&lt;br /&gt;We will start by creating a new project, which we can call Load3DObject. We can create&lt;br /&gt;both the Windows and Xbox 360 game projects. After getting our solution set up, we can&lt;br /&gt;then add an existing project to our solution—the XELibrary from last chapter. Once we&lt;br /&gt;import both the Windows and the Xbox 360 XELibrary projects, we need to reference&lt;br /&gt;them inside of the game projects we created. We reference the XELibrary in our Windows&lt;br /&gt;project and the XELibrary_Xbox360 in our Xbox 360 game project.&lt;br /&gt;After we have our initial setup of our solution file completed, we can jump right in and&lt;br /&gt;add a using statement at the top of our Game1.cs class to access our library:&lt;br /&gt;using XELibrary;&lt;br /&gt;We can set up our private member fields to access the game components in our library:&lt;br /&gt;private FPS fps;&lt;br /&gt;private FirstPersonCamera camera;&lt;br /&gt;private InputHandler input;&lt;br /&gt;The following is our constructor, where we initialize the variables we just set:&lt;br /&gt;public Game1()&lt;br /&gt;{&lt;br /&gt;graphics = new GraphicsDeviceManager(this);&lt;br /&gt;content = new ContentManager(Services);&lt;br /&gt;input = new InputHandler(this);&lt;br /&gt;Components.Add(input);&lt;br /&gt;camera = new FirstPersonCamera(this);&lt;br /&gt;Components.Add(camera);&lt;br /&gt;#if DEBUG&lt;br /&gt;//draw 60 fps and update as often as possible&lt;br /&gt;fps = new FPS(this, true, false);&lt;br /&gt;#else&lt;br /&gt;fps = new FPS(this, true, false);&lt;br /&gt;#endif&lt;br /&gt;Components.Add(fps);&lt;br /&gt;}&lt;br /&gt;With just that little bit of coding (and setup) we now have access to all of the code in our&lt;br /&gt;library. We automatically have a first person camera now and we can handle input as well&lt;br /&gt;as display our frame rate. Game components aren’t too shabby.&lt;br /&gt;As we add content to our pipeline we could pretty easily clutter up our Solution Explorer&lt;br /&gt;pane with all of the files. To help alleviate that problem, we are going to create a&lt;br /&gt;Contents folder with subfolders under it. To start, we will add two subfolders—Models&lt;br /&gt;and Textures—under the Content folder. This is not required, but it really helps keep the&lt;br /&gt;clutter minimal. After doing this we will need to make sure we include that folder inside&lt;br /&gt;Loading 3D Models 115&lt;br /&gt;6&lt;br /&gt;of our Xbox 360 solution, otherwise the content files won’t compile and won’t be&lt;br /&gt;deployed and will cause the demo to not load.&lt;br /&gt;Now with the preliminary work out of the way, we can actually get down to business and&lt;br /&gt;load a 3D object. Find the Spacewar project that we extracted back in Chapter 1,&lt;br /&gt;“Introducing the XNA Framework and XNA Game Studio Express,” and under the&lt;br /&gt;Contents\Models\ folder we need to copy the asteroid1.x file and copy it into our&lt;br /&gt;Solution Explorer’s Contents\Models\ folder. When we do this, XNA Game Studio&lt;br /&gt;Express flags it as XNA Framework Content. Now we can compile the code, which will&lt;br /&gt;also kick off the Content Pipeline. The Content Pipeline kicked off the Content Importer,&lt;br /&gt;shoved the data into the DOM, and then called the Content Processor, which passed it to&lt;br /&gt;the Content Compiler. So when we compile our game, it not only compiles our code, but&lt;br /&gt;also the content.&lt;br /&gt;The Content Compiler threw an error, “Missing asset … \Content\Textures\asteroid1.tga,”&lt;br /&gt;because the .X file we loaded has a reference to a texture inside of it. It references a sibling&lt;br /&gt;folder by the name of Textures. The following is a portion of the asteroid1.x file where it&lt;br /&gt;references the texture in the texture’s sibling folder:&lt;br /&gt;Material phong1SG {&lt;br /&gt;1.0;1.0;1.0;1.000000;;&lt;br /&gt;18.000000;&lt;br /&gt;0.000000;0.000000;0.000000;;&lt;br /&gt;0.000000;0.000000;0.000000;;&lt;br /&gt;TextureFilename {&lt;br /&gt;“..\\textures\\asteroid1.tga”;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;We have that folder, but we did not grab the .tga texture from the Spacewar project. Let’s&lt;br /&gt;do that now and paste it into our Textures folder. Once we do this we can compile again&lt;br /&gt;and it should compile without issues. After it compiles successfully, we can browse to our&lt;br /&gt;/bin/x86/content/models/ and /textures/ folders to see there are a couple of files that were&lt;br /&gt;created at the time we compiled. The Content Compiler took the files and compiled them&lt;br /&gt;into the .xnb files we see here. The compiler gave us an error when it could not find the&lt;br /&gt;texture that was associated with the .X file. We have corrected that and our code (and&lt;br /&gt;content) now compiles successfully.&lt;br /&gt;We could run the code but nothing would be on our screen because we have not actually&lt;br /&gt;told XNA to load and draw the object. We can get that ball rolling by creating a private&lt;br /&gt;member field in our Game1.cs class as follows:&lt;br /&gt;private Model model;&lt;br /&gt;Now we can initialize this variable by actually loading our model in our code. We do this&lt;br /&gt;inside of the LoadGraphicsContent method. The following code has the entire method:&lt;br /&gt;116 CHAPTER 6 Loading and Texturing 3D Objects&lt;br /&gt;protected override void LoadGraphicsContent(bool loadAllContent)&lt;br /&gt;{&lt;br /&gt;if (loadAllContent)&lt;br /&gt;{&lt;br /&gt;// TODO: Load any ResourceManagementMode.Automatic content&lt;br /&gt;model = content.Load&lt;Model&gt;(@”Content\Models\asteroid1”);&lt;br /&gt;}&lt;br /&gt;// TODO: Load any ResourceManagementMode.Manual content&lt;br /&gt;}&lt;br /&gt;The only line we added was the statement inside of the condition, but it is important to&lt;br /&gt;discuss this entire method, as we have just breezed over it in the past chapters. This&lt;br /&gt;method is where we will load all of our graphics content. We have two options when we&lt;br /&gt;load our content: We can let XNA handle the memory management of the resources automatically&lt;br /&gt;by loading our content inside of the condition or we can maintain the memory&lt;br /&gt;management ourselves. This method as well as its counterpart, UnloadGraphicsContent,&lt;br /&gt;gets called at appropriate times. What are these appropriate times? This is a good time to&lt;br /&gt;discuss the logic flow of XNA.&lt;br /&gt;The XNA Framework’s logic flow works something like this:&lt;br /&gt;1. The Main application calls the Game Constructor.&lt;br /&gt;2. The Game Constructor will create any game components and call their constructors.&lt;br /&gt;3. The XNA Framework calls the game’s Initialize method.&lt;br /&gt;4. The XNA Framework calls each of the game component’s Initialize methods.&lt;br /&gt;5. The XNA Framework calls each of the Drawable game component’s&lt;br /&gt;LoadGraphicsContent methods.&lt;br /&gt;6. The XNA Framework calls the game’s LoadGraphicsContent method.&lt;br /&gt;7. The XNA Framework calls the game’s Update method.&lt;br /&gt;8. The XNA Framework calls each of the game component’s Update methods.&lt;br /&gt;9. The XNA Framework calls the game’s Draw method.&lt;br /&gt;10. The XNA Framework calls each of the Drawable game component’s Draw methods.&lt;br /&gt;11. Steps 7 through 10 are repeated many times each second.&lt;br /&gt;12. If the device is lost (user moved the window to another monitor, screen resolution&lt;br /&gt;is changed, window is minimized, etc.) then a call to UnloadGraphicsContent is&lt;br /&gt;made.&lt;br /&gt;13. If the device is reset then we start back at step 6 again.&lt;br /&gt;14. The gamer exits the game.&lt;br /&gt;15. The XNA Framework calls the game’s Dispose method.&lt;br /&gt;Loading 3D Models 117&lt;br /&gt;6&lt;br /&gt;16. The game’s Dispose method calls the base object’s Dispose method, which causes …&lt;br /&gt;17. The XNA Framework calls each of the game component’s Dispose methods.&lt;br /&gt;18. The XNA Framework calls the game’s UnloadGraphicsContent method.&lt;br /&gt;19. The game’s Dispose method gets focus back and the game exits.&lt;br /&gt;Something to note about how the XNA Framework calls the game component’s&lt;br /&gt;Initialize method (and LoadGraphicsContent for drawable game components) is this&lt;br /&gt;only happens once when the game’s Initialize method is kicked off by the framework.&lt;br /&gt;If game components are added later, their Initialize (and LoadGraphicsContent)&lt;br /&gt;methods will not be called. This is important to understand when managing game&lt;br /&gt;components.&lt;br /&gt;At this point we have loaded our 3D content. We have created a private member field to&lt;br /&gt;store the model we added. We actually loaded our model in our code and initialized our&lt;br /&gt;variable. Now we just need to draw the model on the screen. We need to add the following&lt;br /&gt;method to draw a model:&lt;br /&gt;private void DrawModel(ref Model m, ref Matrix world)&lt;br /&gt;{&lt;br /&gt;Matrix[] transforms = new Matrix[m.Bones.Count];&lt;br /&gt;m.CopyAbsoluteBoneTransformsTo(transforms);&lt;br /&gt;foreach (ModelMesh mesh in m.Meshes)&lt;br /&gt;{&lt;br /&gt;foreach (BasicEffect be in mesh.Effects)&lt;br /&gt;{&lt;br /&gt;be.EnableDefaultLighting();&lt;br /&gt;be.Projection = camera.Projection;&lt;br /&gt;be.View = camera.View;&lt;br /&gt;be.World = world * mesh.ParentBone.Transform;&lt;br /&gt;}&lt;br /&gt;mesh.Draw();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;Our DrawModel method takes in a reference to our model as well as a reference to the world&lt;br /&gt;matrix we need to apply to our model. The first two statements get the transforms of each&lt;br /&gt;bone in the model. A model can have a parent bone with children bones associated with&lt;br /&gt;it. This is mainly used in animations, but even if a model does not have animations it&lt;br /&gt;might still have bones and so our code should include this unless we know for certain that&lt;br /&gt;our model does not have any children. The transforms array will contain a transformation&lt;br /&gt;matrix of each mesh of the model that contains its position relative to the parent. By&lt;br /&gt;doing this, we can make sure that each ModelMesh of the parent Model will be drawn at the&lt;br /&gt;right location. This actually happens in the last statement inside of our inner foreach loop.&lt;br /&gt;118 CHAPTER 6 Loading and Texturing 3D Objects&lt;br /&gt;We take the world matrix that the mesh is supposed to be transformed with and we multiply&lt;br /&gt;that transformation with the ModelMesh’s parent’s transformation. This is to make sure&lt;br /&gt;that that each ModelMesh is drawn correctly with the parent mesh.&lt;br /&gt;We did not need to create our own BasicEffect object as XNA will apply one to a mesh&lt;br /&gt;we load. We can override this and will see that in Part V of the book when we talk about&lt;br /&gt;the High Level Shader Language and make our own effect files. For now, we just ensure&lt;br /&gt;that the default lighting is enabled on the effect as well as setting our projection and view&lt;br /&gt;matrices to what our Camera game component has updated it to be. When we did this in&lt;br /&gt;the last chapter, we only moved where we are setting those values. Instead of having an&lt;br /&gt;effect that we are explicitly calling, we are tying into the one that XNA applies to the&lt;br /&gt;Model when it loads it. This is also happening inside of the inner foreach loop so we&lt;br /&gt;could apply different effects to children meshes if we wanted to.&lt;br /&gt;The other thing to notice is the fact that we did not reference our texture anywhere. Because&lt;br /&gt;it was inside of the .X file and the Content Compiler stored that information, the Content&lt;br /&gt;Manager knew where to look for the texture and load it automatically. We will see how to&lt;br /&gt;override the texture through code a little later in this chapter. Let’s just get it to draw with&lt;br /&gt;the normal texture for now! To do that, we need to actually call our DrawModel method&lt;br /&gt;inside of our Draw method with the following code:&lt;br /&gt;world = Matrix.CreateTranslation(new Vector3(0,0,-4000));&lt;br /&gt;DrawModel(ref model, ref world);&lt;br /&gt;The model we are loading is rather large and as such we are going to push it way back&lt;br /&gt;into the world. In fact, we made a modification to our Camera class in our XELibrary. We&lt;br /&gt;originally had our near and far planes set up as 0.0001 and 1000.0, respectively. The thing&lt;br /&gt;about the plane values is that they are floating points, which means there is a finite&lt;br /&gt;amount of precision we can have. We can either have the precision before the decimal&lt;br /&gt;point or after the decimal point, but not both. A lot of times programmers will set the far&lt;br /&gt;plane to a very high number but when that happens the depth buffer (also known as a z&lt;br /&gt;buffer) could have a hard time knowing which objects to draw first. As a result during&lt;br /&gt;game play the screen will almost flicker as different vertices are fighting to be drawn first&lt;br /&gt;and the z buffer is confused because it cannot take into account the minor differences in&lt;br /&gt;the locations of those vertices. Of course, the .0001 near plan we originally had set was&lt;br /&gt;not exactly practical either. At this point having a near plane of 1 and a far plane of&lt;br /&gt;10,000 should meet most of our needs without overly stressing our z buffer. We could&lt;br /&gt;have our far plane even further without causing an adverse effect on the depth buffer.&lt;br /&gt;Finally, we need to create our private member world field that we referenced:&lt;br /&gt;private Matrix world;&lt;br /&gt;Now we can compile and run our code and we should see our asteroid object sitting right&lt;br /&gt;in front of us. This is not extremely exciting, but we have just successfully drawn a .X&lt;br /&gt;model complete with a texture.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-7126532246450793186?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/7126532246450793186/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=7126532246450793186' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/7126532246450793186'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/7126532246450793186'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/loading-3d-models.html' title='Loading 3D Models'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-6268315421024195752</id><published>2008-04-04T21:04:00.001-07:00</published><updated>2008-04-04T21:04:38.402-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='understand'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='pipeline'/><category scheme='http://www.blogger.com/atom/ns#' term='content'/><title type='text'>Understanding the Content Pipeline</title><content type='html'>The Content Pipeline can be used to solve a very real&lt;br /&gt;problem: The content we create for games is typically not&lt;br /&gt;game ready. For example, 3D content is usually stored in a&lt;br /&gt;proprietary format and there is a need to convert the data&lt;br /&gt;before loading it into the game. This is where Content&lt;br /&gt;Pipeline helps out. In general, it can take different files as&lt;br /&gt;input, massage them to get them into a type that we can&lt;br /&gt;work with, and then compile them into a format that can&lt;br /&gt;easily be loaded when our game starts.&lt;br /&gt;The XNA Framework Content Pipeline is made up of&lt;br /&gt;several components. First is the Content Importer, which is&lt;br /&gt;responsible for reading the data that is loaded into the&lt;br /&gt;solution. If there is data in the file the Content Importer&lt;br /&gt;does not know how to map to the content DOM, then the&lt;br /&gt;data is not stored. It only keeps the data it cares about.&lt;br /&gt;Once the importer is done reading in the data, it passes it&lt;br /&gt;along to the Content DOM, which stores the strongly&lt;br /&gt;typed data. It is then passed from the Content DOM to a&lt;br /&gt;Content Processor, which then passes it to a Content&lt;br /&gt;Compiler. If the compilation fails we get a nice message&lt;br /&gt;inside of the IDE that tells us what happened: We do not&lt;br /&gt;114 CHAPTER 6 Loading and Texturing 3D Objects&lt;br /&gt;have to wait and see if it is going to load at runtime, and this is a huge improvement over&lt;br /&gt;how things used to work. The compiler actually builds files that are read in at runtime.&lt;br /&gt;These files typically have an .xnb file extension. Audio files actually create .xgs, .xwb, and&lt;br /&gt;.xsb files for the actual sound project, wave bank, and sound bank content. We discuss&lt;br /&gt;the sound and how it relates to the Content Pipeline in the next chapter. The Content&lt;br /&gt;Pipeline is smart enough to not recompile any content that has not changed since the&lt;br /&gt;last build. Finally, after all of the content is compiled into files, they are read in via the&lt;br /&gt;Content Manager at runtime so our games can consume the content. We have been using&lt;br /&gt;the Content Manager since our very first application in Chapter 2, “XNA and the Xbox&lt;br /&gt;360.” We created an instance to the Content Manager in our game’s constructor like the&lt;br /&gt;following:&lt;br /&gt;content = new ContentManager(Services);&lt;br /&gt;Fortunately, when we use the Content Manager we do not need to actually dispose of our&lt;br /&gt;objects, as it handles disposing of our content itself. It does this in the following code,&lt;br /&gt;which is always included in our new game projects:&lt;br /&gt;protected override void UnloadGraphicsContent(bool unloadAllContent)&lt;br /&gt;{&lt;br /&gt;if (unloadAllContent == true)&lt;br /&gt;{&lt;br /&gt;content.Unload();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;The code simply calls the Unload method on the instance of the content manager. This&lt;br /&gt;then goes through each of the objects that have been loaded and disposes of them. We&lt;br /&gt;discuss the counter part of this method in the next section. The LoadGraphicsContent&lt;br /&gt;method does the actual loading of the data.&lt;br /&gt;As we add content to our project that is recognizable as XNA Framework content, it goes&lt;br /&gt;through the process just described. The Properties window inside of the Visual C# Express&lt;br /&gt;IDE will show an asset name that we can modify. If we add content types that are not&lt;br /&gt;recognized, we can change the XNA Framework Content boolean value to true. We would&lt;br /&gt;then need to fill in the Content Importer and Content Processor properties, specifying&lt;br /&gt;how to turn the unknown content type into a format that XNA can recognize. This&lt;br /&gt;would require a custom importer and processor that we discuss building in Chapter 8,&lt;br /&gt;“Extending the Content Pipeline,” where we will learn about extending the pipeline.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-6268315421024195752?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/6268315421024195752/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=6268315421024195752' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/6268315421024195752'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/6268315421024195752'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/understanding-content-pipeline.html' title='Understanding the Content Pipeline'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-3560749931204994715</id><published>2008-04-04T21:03:00.000-07:00</published><updated>2008-04-04T21:04:16.092-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='split'/><category scheme='http://www.blogger.com/atom/ns#' term='screen'/><category scheme='http://www.blogger.com/atom/ns#' term='create'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>Creating a Split Screen</title><content type='html'>Now that we know how to set up our camera and accept input, we can look into how our&lt;br /&gt;code will need to change to handle multiple players in a split-screen game. To start, we&lt;br /&gt;need to make a copy of the InputDemo project we just finished. We can rename the&lt;br /&gt;project SplitScreen. After we have our solution and projects renamed (complete with our&lt;br /&gt;assembly GUID and title) we can look at the code we will need to change to accomplish a&lt;br /&gt;split-screen mode of play.&lt;br /&gt;To create a split screen, we need to two different viewports. We have only been using one&lt;br /&gt;up until now and we actually retrieved it in our camera’s Initialization method. We&lt;br /&gt;simply grabbed the GraphicsDevice.Viewport property to get our camera’s viewport.&lt;br /&gt;Because we want to display two screens in one we need to define our two new viewports&lt;br /&gt;and then let the cameras (we will need two cameras) know about them so we can get the&lt;br /&gt;desired effect. To start we will need to add the following private member fields to our&lt;br /&gt;Game1.cs code:&lt;br /&gt;private Viewport defaultViewport;&lt;br /&gt;private Viewport topViewport;&lt;br /&gt;private Viewport bottomViewport;&lt;br /&gt;private separatorViewport;&lt;br /&gt;private bool twoPlayers = true;&lt;br /&gt;private FirstPersonCamera camera2;&lt;br /&gt;Then at the end of our LoadGraphicsContent method we will need to define those viewports&lt;br /&gt;and create our cameras and pass the new values. We do this in the following code:&lt;br /&gt;if (twoPlayers)&lt;br /&gt;{&lt;br /&gt;defaultViewport = graphics.GraphicsDevice.Viewport;&lt;br /&gt;topViewport = defaultViewport;&lt;br /&gt;bottomViewport = defaultViewport;&lt;br /&gt;topViewport.Height = topViewport.Height / 2;&lt;br /&gt;separatorViewport.Y = topViewport.Height – 1;&lt;br /&gt;separatorViewport.Height = 3;&lt;br /&gt;bottomViewport.Y = topViewport.Height + 1;&lt;br /&gt;bottomViewport.Height = (bottomViewport.Height / 2) - 1;&lt;br /&gt;camera.Viewport = topViewport;&lt;br /&gt;106 CHAPTER 5 Input Devices and Cameras&lt;br /&gt;camera2 = new FirstPersonCamera(this);&lt;br /&gt;camera2.Viewport = bottomViewport;&lt;br /&gt;camera2.Position = new Vector3(0.0f, 0.0f, -3.0f);&lt;br /&gt;camera2.Orientation = new Vector3(0.0f, 0.0f, 1.0f);&lt;br /&gt;camera2.PlayerIndex = PlayerIndex.Two;&lt;br /&gt;Components.Add(camera2);&lt;br /&gt;}&lt;br /&gt;We discussed briefly that we would need more than one camera to pull this off. This is&lt;br /&gt;because we have our view and projection matrices associated with our camera class&lt;br /&gt;(which we should). It makes sense that we will have two cameras because the camera is&lt;br /&gt;showing what the player is seeing. Each player needs his or her own view into the game.&lt;br /&gt;Our initial camera is still set up in our game’s constructor but our second camera will get&lt;br /&gt;added here. Our first camera gets the default viewport associated with it. The first thing&lt;br /&gt;the preceding code is doing is checking to see if we are in a two-player game. For a real&lt;br /&gt;game, this should be determined by an options menu or something similar, but for now&lt;br /&gt;we have just initialized the value to true when we initialized the twoPlayer variable.&lt;br /&gt;Inside of the two-player condition the first thing we do is set our default viewport to what&lt;br /&gt;we are currently using (the graphic device’s viewport). Then we set our top viewport to&lt;br /&gt;the same value. We also initialize our bottomViewport to our defaultViewport value. The&lt;br /&gt;final thing we do with our viewports is resize them to account for two players. We divide&lt;br /&gt;the height in two (we are making two horizontal viewports) on both. We then set our&lt;br /&gt;bottom viewport’s Y property to be one more than the height of our bottom. This effectively&lt;br /&gt;puts the bottom viewport right underneath our top viewport.&lt;br /&gt;While still in the two-player condition we change our first camera’s viewport to use the&lt;br /&gt;top viewport. Then we set up our second camera by setting more properties. Not only&lt;br /&gt;do we set the viewport for this camera to the bottom viewport we have, but we also&lt;br /&gt;set a new camera position as well as the orientation of the camera. Finally, we set the&lt;br /&gt;player index.&lt;br /&gt;None of these properties is exposed from our camera object, so we need to open our&lt;br /&gt;Camera.cs file and make some changes to account for this. First, we need to add a new&lt;br /&gt;private member field to hold our player index. We just assumed it was player 1 before. We&lt;br /&gt;can set up our protected (so our FirstPersonCamera class can access it) index as an&lt;br /&gt;integer as follows:&lt;br /&gt;protected int playerIndex = 0;&lt;br /&gt;Now, we can actually modify our input code that controls our camera to use this index&lt;br /&gt;instead of the hard-coded value 0 for our game pads. In the camera’s Update method we&lt;br /&gt;can change any instance of input.GamePads[0] to input.GamePads[playerIndex]. We also&lt;br /&gt;need to do the same for the FirstPersonCamera object. We did not update the keyboard&lt;br /&gt;code and will not for the sake of time. However, to implement multiple users where both&lt;br /&gt;can use the keyboard we should create a mapping for each player and check accordingly.&lt;br /&gt;In general, it is a good practice to have a keyboard mapping so that if gamers do not like&lt;br /&gt;Creating a Split Screen 107&lt;br /&gt;5&lt;br /&gt;the controls we have defined in our games then they have a way to change them so it&lt;br /&gt;works more logically for them. The same can be said about creating a mapping for the&lt;br /&gt;game pads but many games simply give a choice of a couple of layouts. Because the code&lt;br /&gt;does not implement a keyboard mapping, the only way for us to control the separate&lt;br /&gt;screens differently is by having two game pads hooked up to our PC or Xbox 360.&lt;br /&gt;After we have changed our camera to take the player index into consideration before&lt;br /&gt;reading values from our game pad, we can add the following properties to our code:&lt;br /&gt;public PlayerIndex PlayerIndex&lt;br /&gt;{&lt;br /&gt;get { return ((PlayerIndex)playerIndex); }&lt;br /&gt;set { playerIndex = (int)value; }&lt;br /&gt;}&lt;br /&gt;public Vector3 Position&lt;br /&gt;{&lt;br /&gt;get { return (cameraPosition); }&lt;br /&gt;set { cameraPosition = value; }&lt;br /&gt;}&lt;br /&gt;public Vector3 Orientation&lt;br /&gt;{&lt;br /&gt;get { return (cameraReference); }&lt;br /&gt;set { cameraReference = value; }&lt;br /&gt;}&lt;br /&gt;public Vector3 Target&lt;br /&gt;{&lt;br /&gt;get { return (cameraTarget); }&lt;br /&gt;set { cameraTarget = value; }&lt;br /&gt;}&lt;br /&gt;public Viewport Viewport&lt;br /&gt;{&lt;br /&gt;get&lt;br /&gt;{&lt;br /&gt;if (viewport == null)&lt;br /&gt;viewport = graphics.GraphicsDevice.Viewport;&lt;br /&gt;return ((Viewport)viewport);&lt;br /&gt;}&lt;br /&gt;set&lt;br /&gt;{&lt;br /&gt;viewport = value;&lt;br /&gt;InitializeCamera();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;108 CHAPTER 5 Input Devices and Cameras&lt;br /&gt;We are simply exposing the camera’s position, orientation (reference), and target variables.&lt;br /&gt;For the player index property we are casting it to a PlayerIndex enumeration type.&lt;br /&gt;The final property is the Viewport property. We first check to see if our viewport variable&lt;br /&gt;is null and if so we set it to the graphics device’s viewport. When we set our Viewport&lt;br /&gt;property, we also call our InitializeCamera method again so it can recalculate its view&lt;br /&gt;and projection matrices. We need to set up a private member field for our viewport. We&lt;br /&gt;will allow it to have a default null value so we can declare it as follows:&lt;br /&gt;private Viewport? viewport;&lt;br /&gt;Because we are utilizing the Viewport type we will need to add the following using statement&lt;br /&gt;to our code:&lt;br /&gt;using Microsoft.Xna.Framework.Graphics;&lt;br /&gt;The only thing left for us to do now is to actually update our game’s drawing code to&lt;br /&gt;draw our scene twice. Because we are going to have to draw our scene twice (once for&lt;br /&gt;each camera) we will need to refactor our Draw code into a DrawScene method and pass in&lt;br /&gt;a camera reference. Our new code for the new Draw method is as follows:&lt;br /&gt;protected override void Draw(GameTime gameTime)&lt;br /&gt;{&lt;br /&gt;graphics.GraphicsDevice.Viewport = camera.Viewport;&lt;br /&gt;DrawScene(gameTime, camera);&lt;br /&gt;if (twoPlayers)&lt;br /&gt;{&lt;br /&gt;graphics.GraphicsDevice.Viewport = camera2.Viewport;&lt;br /&gt;DrawScene(gameTime, camera2);&lt;br /&gt;//now clear the thick horizontal line between the two screens&lt;br /&gt;graphics.GraphicsDevice.Viewport = separatorViewport;&lt;br /&gt;graphics.GraphicsDevice.Clear(Color.Black);&lt;br /&gt;}&lt;br /&gt;base.Draw(gameTime);&lt;br /&gt;}&lt;br /&gt;We took all of the code that was inside of this method and put it into a new method&lt;br /&gt;DrawScene(GameTime gameTime, Camera camera). The code we put into the DrawScene&lt;br /&gt;method did not change from how it looked when it resided inside of the Draw method.&lt;br /&gt;The first thing we do with the preceding code is set our graphics device’s viewport to be&lt;br /&gt;what our camera’s viewport is. We then draw the scene passing in our camera. Then we&lt;br /&gt;check to see if we have two players; if so we set the viewport appropriately and finally&lt;br /&gt;draw the scene for that camera. We can run our application and see that it is using a split&lt;br /&gt;screen! The screen shot of this split screen demo can be seen in Figure 5.1.&lt;br /&gt;Creating a Split Screen 109&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-3560749931204994715?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/3560749931204994715/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=3560749931204994715' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/3560749931204994715'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/3560749931204994715'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/creating-split-screen.html' title='Creating a Split Screen'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-6533476828409402981</id><published>2008-04-04T21:02:00.000-07:00</published><updated>2008-04-04T21:03:33.413-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='create'/><category scheme='http://www.blogger.com/atom/ns#' term='fps'/><category scheme='http://www.blogger.com/atom/ns#' term='first person camera'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>Creating a First Person Camera</title><content type='html'>We can build on our stationary camera by adding a first person camera. The main thing&lt;br /&gt;we want to do is to add in a way to move back and forth and to each side. Before we&lt;br /&gt;start, we should create a new camera class and inherit from the one we have. We can call&lt;br /&gt;this new class FirstPersonCamera. The following is the Update method for this new class:&lt;br /&gt;public override void Update(GameTime gameTime)&lt;br /&gt;{&lt;br /&gt;// TODO: Add your update code here&lt;br /&gt;//reset movement vector&lt;br /&gt;movement = Vector3.Zero;&lt;br /&gt;if (input.KeyboardState.IsKeyDown(Keys.A) ||&lt;br /&gt;(input.GamePads[0].ThumbSticks.Left.X &lt; 0))&lt;br /&gt;{&lt;br /&gt;movement.X—;&lt;br /&gt;Creating a First Person Camera 103&lt;br /&gt;3&lt;br /&gt;LISTING 5.1 Continued&lt;br /&gt;}&lt;br /&gt;if (input.KeyboardState.IsKeyDown(Keys.D) ||&lt;br /&gt;(input.GamePads[0].ThumbSticks.Left.X &gt; 0))&lt;br /&gt;{&lt;br /&gt;movement.X++;&lt;br /&gt;}&lt;br /&gt;if (input.KeyboardState.IsKeyDown(Keys.S) ||&lt;br /&gt;(input.GamePads[0].ThumbSticks.Left.Y &lt; 0))&lt;br /&gt;{&lt;br /&gt;movement.Z++;&lt;br /&gt;}&lt;br /&gt;if (input.KeyboardState.IsKeyDown(Keys.W) ||&lt;br /&gt;(input.GamePads[0].ThumbSticks.Left.Y &gt; 0))&lt;br /&gt;{&lt;br /&gt;movement.Z—;&lt;br /&gt;}&lt;br /&gt;//make sure we don’t increase speed if pushing up and over (diagonal)&lt;br /&gt;if (movement.LengthSquared() != 0)&lt;br /&gt;movement.Normalize();&lt;br /&gt;base.Update(gameTime);&lt;br /&gt;}&lt;br /&gt;The conditional logic should look familiar. It is identical to our stationary camera, except&lt;br /&gt;we changed where we were reading the input and what values it updated. We are reading&lt;br /&gt;the A, S, W, D keys and the left thumb stick. We are not looking at the mouse for movement.&lt;br /&gt;The value we are setting is a movement vector. We are only setting the X (left and&lt;br /&gt;right) and Z (back and forth) values. At the end of the conditions we are normalizing our&lt;br /&gt;vector as long as the length squared of the vector is not zero. This makes sure that we are&lt;br /&gt;not allowing faster movement just because the user is moving diagonally. There is no&lt;br /&gt;more code in the FirstPersonCamera object. The rest of the changes were made back on&lt;br /&gt;our original camera object.&lt;br /&gt;We declared the movement as a protected member field of type Vector3 called movement&lt;br /&gt;inside of our original Camera object. We also declared a constant value for our movement&lt;br /&gt;speed. Both of these are listed here:&lt;br /&gt;protected Vector3 movement = Vector3.Zero;&lt;br /&gt;private const float moveRate = 120.0f;&lt;br /&gt;We also set the access modifier of our input field to protected so our FirstPersonCamera&lt;br /&gt;could access it:&lt;br /&gt;protected IInputHandler input;&lt;br /&gt;104 CHAPTER 5 Input Devices and Cameras&lt;br /&gt;Finally we updated the last part of our Update method to take the movement into&lt;br /&gt;account when transforming our camera:&lt;br /&gt;//update movement (none for this base class)&lt;br /&gt;movement *= (moveRate * timeDelta);&lt;br /&gt;Matrix rotationMatrix;&lt;br /&gt;Vector3 transformedReference;&lt;br /&gt;Matrix.CreateRotationY(MathHelper.ToRadians(cameraYaw), out rotationMatrix);&lt;br /&gt;if (movement != Vector3.Zero)&lt;br /&gt;{&lt;br /&gt;Vector3.Transform(ref movement, ref rotationMatrix, out movement);&lt;br /&gt;cameraPosition += movement;&lt;br /&gt;}&lt;br /&gt;//add in pitch to the rotation&lt;br /&gt;rotationMatrix = Matrix.CreateRotationX(MathHelper.ToRadians(cameraPitch)) *&lt;br /&gt;rotationMatrix;&lt;br /&gt;// Create a vector pointing the direction the camera is facing.&lt;br /&gt;Vector3.Transform(ref cameraReference, ref rotationMatrix,&lt;br /&gt;out transformedReference);&lt;br /&gt;// Calculate the position the camera is looking at.&lt;br /&gt;Vector3.Add(ref cameraPosition, ref transformedReference, out cameraTarget);&lt;br /&gt;Matrix.CreateLookAt(ref cameraPosition, ref cameraTarget, ref cameraUpVector,&lt;br /&gt;out view);&lt;br /&gt;Besides just moving our local variables closer together, the only things that changed are&lt;br /&gt;the items in bold type. We take our movement vector and apply our move rate to it&lt;br /&gt;(taking into account our time delta, of course). The second portion is the key. We transformed&lt;br /&gt;our movement vector by our rotation matrix. This keeps us from just looking in a&lt;br /&gt;direction but continuing to move straight ahead. By transforming our movement vector&lt;br /&gt;by our rotation matrix we actually move in the direction we are looking! Well, the movement&lt;br /&gt;actually happens in the next statement when we add this movement vector to our&lt;br /&gt;current camera position. We wrapped all of this in a condition to see if any movement&lt;br /&gt;happened because we do not want to take a performance hit to do the math if we did not&lt;br /&gt;move.&lt;br /&gt;Another thing to note is that because we were creating a first person camera we only&lt;br /&gt;transformed our movement vector by the yaw portion of our rotation matrix. We did&lt;br /&gt;not include the pitch, as that would have allowed us to “fly.” If we did want to create a&lt;br /&gt;flying camera instead, we could simply move this following statement before the code&lt;br /&gt;that is bold:&lt;br /&gt;105&lt;br /&gt;5&lt;br /&gt;//add in pitch to the rotation&lt;br /&gt;rotationMatrix = Matrix.CreateRotationX(MathHelper.ToRadians(cameraPitch)) *&lt;br /&gt;rotationMatrix;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-6533476828409402981?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/6533476828409402981/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=6533476828409402981' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/6533476828409402981'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/6533476828409402981'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/creating-first-person-camera.html' title='Creating a First Person Camera'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-4153656977280711229</id><published>2008-04-03T21:42:00.001-07:00</published><updated>2008-04-03T21:42:46.244-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='camera'/><category scheme='http://www.blogger.com/atom/ns#' term='stationary'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>Creating a Stationary Camera</title><content type='html'>Now that we know how to utilize our input, we can get working on implementing our&lt;br /&gt;stationary camera. We actually have most of this done, but we need to add pitching as&lt;br /&gt;well as the yaw we already have. One use for a stationary camera is to look at an object&lt;br /&gt;and follow it by rotating as needed. This is commonly used in racing game replay mode.&lt;br /&gt;Before we dig into the camera changes, though, let’s add a few more rectangles to our&lt;br /&gt;world. We can do this by adding the following code to the end of our demo’s Update&lt;br /&gt;method:&lt;br /&gt;world = Matrix.CreateTranslation(new Vector3(8.0f, 0, -10.0f));&lt;br /&gt;DrawRectangle(ref world);&lt;br /&gt;world = Matrix.CreateTranslation(new Vector3(8.0f, 0, -6.0f));&lt;br /&gt;DrawRectangle(ref world);&lt;br /&gt;world = Matrix.CreateRotationY(Matrix.CreateTranslation(new Vector3(3.0f, 0, 10.0f));&lt;br /&gt;DrawRectangle(ref world);&lt;br /&gt;We should also change our cull mode to None so that as we rotate around that we will&lt;br /&gt;always see our rectangles. We can do that by calling the following code at the top of our&lt;br /&gt;game’s Draw method:&lt;br /&gt;graphics.GraphicsDevice.RenderState.CullMode = CullMode.None;&lt;br /&gt;To get our camera updated we need to modify our camera class a little bit. First we need&lt;br /&gt;to declare a private member field as follows:&lt;br /&gt;private float cameraPitch = 0.0f;&lt;br /&gt;Now we can modify the Update method to set our camera pitch. Remember, pitching&lt;br /&gt;refers to rotating around the x axis. To calculate this we simply take the code we did for&lt;br /&gt;calculating the yaw and replace our reference to the y axis with the x axis. The following&lt;br /&gt;is the code to check our keyboard and game pad:&lt;br /&gt;if (input.KeyboardState.IsKeyDown(Keys.Down) ||&lt;br /&gt;(input.GamePads[0].ThumbSticks.Right.Y &lt; 0))&lt;br /&gt;{&lt;br /&gt;cameraPitch -= (spinRate * timeDelta);&lt;br /&gt;}&lt;br /&gt;if (input.KeyboardState.IsKeyDown(Keys.Up) ||&lt;br /&gt;(input.GamePads[0].ThumbSticks.Right.Y &gt; 0))&lt;br /&gt;{&lt;br /&gt;cameraPitch += (spinRate * timeDelta);&lt;br /&gt;}&lt;br /&gt;100 CHAPTER 5 Input Devices and Cameras&lt;br /&gt;No surprises there, and we need to do the same thing with our mouse code. Inside of the&lt;br /&gt;#if !XBOX360 compilation directive we already have we can add the following code:&lt;br /&gt;if ((input.PreviousMouseState.Y &gt; input.MouseState.Y) &amp;&amp;&lt;br /&gt;(input.MouseState.LeftButton == ButtonState.Pressed))&lt;br /&gt;{&lt;br /&gt;cameraPitch += (spinRate * timeDelta);&lt;br /&gt;}&lt;br /&gt;else if ((input.PreviousMouseState.Y &lt; input.MouseState.Y) &amp;&amp;&lt;br /&gt;(input.MouseState.LeftButton == ButtonState.Pressed))&lt;br /&gt;{&lt;br /&gt;cameraPitch -= (spinRate * timeDelta);&lt;br /&gt;}&lt;br /&gt;We want to clamp our values so we do not rotate over 90 degrees in either direction:&lt;br /&gt;if (cameraPitch &gt; 89)&lt;br /&gt;cameraPitch = 89;&lt;br /&gt;if (cameraPitch &lt; -89)&lt;br /&gt;cameraPitch = -89;&lt;br /&gt;Finally, we need to update our rotation matrix to include our pitch value. Here is the&lt;br /&gt;updated calculation:&lt;br /&gt;Matrix rotationMatrix;&lt;br /&gt;Matrix.CreateRotationY(MathHelper.ToRadians(cameraYaw), out rotationMatrix);&lt;br /&gt;//add in pitch to the rotation&lt;br /&gt;rotationMatrix = Matrix.CreateRotationX(MathHelper.ToRadians(cameraPitch)) *&lt;br /&gt;rotationMatrix;&lt;br /&gt;The last statement is the only thing we added. We just added our pitch to the rotation&lt;br /&gt;matrix that was already being used to transform our camera. The full Update listing can&lt;br /&gt;be found in Listing 5.1.&lt;br /&gt;LISTING 5.1 Our stationary camera’ s Update method&lt;br /&gt;public override void Update(GameTime gameTime)&lt;br /&gt;{&lt;br /&gt;float timeDelta = (float)gameTime.ElapsedGameTime.TotalSeconds;&lt;br /&gt;if (input.KeyboardState.IsKeyDown(Keys.Left) ||&lt;br /&gt;(input.GamePads[0].ThumbSticks.Right.X &lt; 0))&lt;br /&gt;{&lt;br /&gt;cameraYaw += (spinRate * timeDelta);&lt;br /&gt;}&lt;br /&gt;if (input.KeyboardState.IsKeyDown(Keys.Right) ||&lt;br /&gt;(input.GamePads[0].ThumbSticks.Right.X &gt; 0))&lt;br /&gt;Creating a Stationary Camera 101&lt;br /&gt;5&lt;br /&gt;{&lt;br /&gt;cameraYaw -= (spinRate * timeDelta);&lt;br /&gt;}&lt;br /&gt;if (input.KeyboardState.IsKeyDown(Keys.Down) ||&lt;br /&gt;(input.GamePads[0].ThumbSticks.Right.Y &lt; 0))&lt;br /&gt;{&lt;br /&gt;cameraPitch -= (spinRate * timeDelta);&lt;br /&gt;}&lt;br /&gt;if (input.KeyboardState.IsKeyDown(Keys.Up) ||&lt;br /&gt;(input.GamePads[0].ThumbSticks.Right.Y &gt; 0))&lt;br /&gt;{&lt;br /&gt;cameraPitch += (spinRate * timeDelta);&lt;br /&gt;}&lt;br /&gt;#if !XBOX360&lt;br /&gt;if ((input.PreviousMouseState.X &gt; input.MouseState.X) &amp;&amp;&lt;br /&gt;(input.MouseState.LeftButton == ButtonState.Pressed))&lt;br /&gt;{&lt;br /&gt;cameraYaw += (spinRate * timeDelta);&lt;br /&gt;}&lt;br /&gt;else if ((input.PreviousMouseState.X &lt; input.MouseState.X) &amp;&amp;&lt;br /&gt;(input.MouseState.LeftButton == ButtonState.Pressed))&lt;br /&gt;{&lt;br /&gt;cameraYaw -= (spinRate * timeDelta);&lt;br /&gt;}&lt;br /&gt;if ((input.PreviousMouseState.Y &gt; input.MouseState.Y) &amp;&amp;&lt;br /&gt;(input.MouseState.LeftButton == ButtonState.Pressed))&lt;br /&gt;{&lt;br /&gt;cameraPitch += (spinRate * timeDelta);&lt;br /&gt;}&lt;br /&gt;else if ((input.PreviousMouseState.Y &lt; input.MouseState.Y) &amp;&amp;&lt;br /&gt;(input.MouseState.LeftButton == ButtonState.Pressed))&lt;br /&gt;{&lt;br /&gt;cameraPitch -= (spinRate * timeDelta);&lt;br /&gt;}&lt;br /&gt;#endif&lt;br /&gt;//reset camera angle if needed&lt;br /&gt;if (cameraYaw &gt; 360)&lt;br /&gt;cameraYaw -= 360;&lt;br /&gt;else if (cameraYaw &lt; 0)&lt;br /&gt;102 CHAPTER 5 Input Devices and Cameras&lt;br /&gt;LISTING 5.1 Continued&lt;br /&gt;cameraYaw += 360;&lt;br /&gt;//keep camera from rotating a full 90 degrees in either direction&lt;br /&gt;if (cameraPitch &gt; 89)&lt;br /&gt;cameraPitch = 89;&lt;br /&gt;if (cameraPitch &lt; -89)&lt;br /&gt;cameraPitch = -89;&lt;br /&gt;Matrix rotationMatrix;&lt;br /&gt;Matrix.CreateRotationY(MathHelper.ToRadians(cameraYaw),&lt;br /&gt;out rotationMatrix);&lt;br /&gt;//add in pitch to the rotation&lt;br /&gt;rotationMatrix = Matrix.CreateRotationX(MathHelper.ToRadians(cameraPitch))&lt;br /&gt;* rotationMatrix;&lt;br /&gt;// Create a vector pointing the direction the camera is facing.&lt;br /&gt;Vector3 transformedReference;&lt;br /&gt;Vector3.Transform(ref cameraReference, ref rotationMatrix,&lt;br /&gt;out transformedReference);&lt;br /&gt;// Calculate the position the camera is looking at.&lt;br /&gt;Vector3.Add(ref cameraPosition, ref transformedReference, out cameraTarget);&lt;br /&gt;Matrix.CreateLookAt(ref cameraPosition, ref cameraTarget, ref cameraUpVector,&lt;br /&gt;out view);&lt;br /&gt;base.Update(gameTime);&lt;br /&gt;}&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-4153656977280711229?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/4153656977280711229/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=4153656977280711229' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/4153656977280711229'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/4153656977280711229'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/creating-stationary-camera.html' title='Creating a Stationary Camera'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-4304838086486703417</id><published>2008-04-03T21:41:00.001-07:00</published><updated>2008-04-03T21:41:33.877-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='device'/><category scheme='http://www.blogger.com/atom/ns#' term='input'/><category scheme='http://www.blogger.com/atom/ns#' term='mouse'/><title type='text'>Working with mouse Devices</title><content type='html'>This input device is only available for Windows, so if we are deploying our game for the&lt;br /&gt;Xbox 360 we will need to put the XBOX360 compilation directive check we learned about&lt;br /&gt;in Chapter 2 around any code that references the mouse as an input device. So we will&lt;br /&gt;create a private member field with this preprocessor check inside of our InputHandler&lt;br /&gt;class. We need to set up a private member field to hold our previous mouse state and&lt;br /&gt;another one to hold our current mouse state:&lt;br /&gt;#if !XBOX360&lt;br /&gt;private MouseState mouseState;&lt;br /&gt;private MouseState prevMouseState;&lt;br /&gt;#endif&lt;br /&gt;Then in our constructor we tell XNA that we want the mouse icon visible in our window&lt;br /&gt;and we store our current mouse state:&lt;br /&gt;#if !XBOX360&lt;br /&gt;Game.IsMouseVisible = true;&lt;br /&gt;prevMouseState = Mouse.GetState();&lt;br /&gt;#endif&lt;br /&gt;In our Update method of the input handler game component we need to set the previous&lt;br /&gt;state to what our current state is and then reset our current state as follows:&lt;br /&gt;#if !XBOX360&lt;br /&gt;prevMouseState = mouseState;&lt;br /&gt;mouseState = Mouse.GetState();&lt;br /&gt;#endif&lt;br /&gt;98 CHAPTER 5 Input Devices and Cameras&lt;br /&gt;Now we need to expose these internal fields so our camera (and any other) object can get&lt;br /&gt;their values. First we need to add the properties to our interface as follows:&lt;br /&gt;#if !XBOX360&lt;br /&gt;MouseState MouseState { get; }&lt;br /&gt;MouseState PreviousMouseState { get; }&lt;br /&gt;#endif&lt;br /&gt;Now we can implement those properties in our class:&lt;br /&gt;#if !XBOX360&lt;br /&gt;public MouseState MouseState&lt;br /&gt;{&lt;br /&gt;get { return(mouseState); }&lt;br /&gt;}&lt;br /&gt;public MouseState PreviousMouseState&lt;br /&gt;{&lt;br /&gt;get { return(prevMouseState); }&lt;br /&gt;}&lt;br /&gt;#endif&lt;br /&gt;In our camera’s Update method we want to get the latest state of our mouse and compare&lt;br /&gt;the current X value to the previous X value to determine if we moved the mouse left or&lt;br /&gt;right. We also want to check if the left mouse button is pushed before updating our&lt;br /&gt;cameraYaw variable. Of course, all of this is wrapped in our compilation preprocessor&lt;br /&gt;condition as follows:&lt;br /&gt;#if !XBOX360&lt;br /&gt;if ((input.PreviousMouseState.X &gt; input.MouseState.X) &amp;&amp;&lt;br /&gt;(input.MouseState.LeftButton == ButtonState.Pressed))&lt;br /&gt;{&lt;br /&gt;cameraYaw += (spinRate * timeDelta);&lt;br /&gt;}&lt;br /&gt;else if ((input.PreviousMouseState.X &lt; input.MouseState.X) &amp;&amp;&lt;br /&gt;(input.MouseState.LeftButton == ButtonState.Pressed))&lt;br /&gt;{&lt;br /&gt;cameraYaw -= (spinRate * timeDelta);&lt;br /&gt;}&lt;br /&gt;#endif&lt;br /&gt;We can compile and run the code and test the latest functionality on Windows. If the&lt;br /&gt;preprocessor checks are in place correctly, we should be able to deploy this demo to the&lt;br /&gt;Xbox 360 as well, although it will not do anything different than it did before we added&lt;br /&gt;the mouse support.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-4304838086486703417?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/4304838086486703417/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=4304838086486703417' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/4304838086486703417'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/4304838086486703417'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/working-with-mouse-devices_03.html' title='Working with mouse Devices'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-3690563515209469955</id><published>2008-04-03T21:40:00.002-07:00</published><updated>2008-04-03T21:41:00.179-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='device'/><category scheme='http://www.blogger.com/atom/ns#' term='input'/><category scheme='http://www.blogger.com/atom/ns#' term='gamepad'/><title type='text'>Working with gamepad Devices</title><content type='html'>The Microsoft Xbox 360 wired controller works on the PC. XNA provides us with helper&lt;br /&gt;classes that make it very easy to determine the state of our game pad. The template&lt;br /&gt;already provided one call to the game pad helper class. This call is also in the Update&lt;br /&gt;method. Let’s take a look at what is provided for us already.&lt;br /&gt;if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)&lt;br /&gt;this.Exit();&lt;br /&gt;The template is calling the built-in XNA class GamePad and calling its GetState method&lt;br /&gt;passing in which player’s controller they want to check. The template then checks the&lt;br /&gt;Back button on that controller to see if it has been pressed. If the controller’s Back button&lt;br /&gt;has been pressed, the game exits. Now, that was pretty straightforward. To be consistent&lt;br /&gt;we can use our input class to check for the condition.&lt;br /&gt;Before we can do that, we need to update our interface and add the appropriate property&lt;br /&gt;as well as actually getting the game pad state just like we did for our keyboard. Let’s jump&lt;br /&gt;to our input handler code and do some of these things. We can start by adding a property&lt;br /&gt;to get to our list of game pads in our interface:&lt;br /&gt;GamePadState[] GamePads { get; }&lt;br /&gt;Now we can create the member field and property to get that field like the following code:&lt;br /&gt;private GamePadState[] gamePads = new GamePadState[4];&lt;br /&gt;public GamePadState[] GamePads&lt;br /&gt;{&lt;br /&gt;get { return(gamePads); }&lt;br /&gt;}&lt;br /&gt;Working with Input Devices 95&lt;br /&gt;5&lt;br /&gt;We need to initialize each game pad state and can do that in the Update method of the&lt;br /&gt;input handler object:&lt;br /&gt;gamePads[0] = GamePad.GetState(PlayerIndex.One);&lt;br /&gt;gamePads[1] = GamePad.GetState(PlayerIndex.Two);&lt;br /&gt;gamePads[2] = GamePad.GetState(PlayerIndex.Three);&lt;br /&gt;gamePads[3] = GamePad.GetState(PlayerIndex.Four);&lt;br /&gt;Now, let’s remove the code that checks to see if the Back button is pressed on player one’s&lt;br /&gt;game pad from our demo. We can add this code in the Update method of our&lt;br /&gt;InputHandler game component to get the same effect:&lt;br /&gt;if (gamePads[0].Buttons.Back == ButtonState.Pressed)&lt;br /&gt;Game.Exit();&lt;br /&gt;Let’s update our yaw rotation code inside of the camera game component so that we can&lt;br /&gt;get the same result with our controller. We can modify our existing code that checks for&lt;br /&gt;left and right to also handle input from our controller. So we modify our two conditional&lt;br /&gt;statements that set the cameraYaw to also check the right thumb stick state of the game&lt;br /&gt;pad we are examining:&lt;br /&gt;if (input.KeyboardState.IsKeyDown(Keys.Left) ||&lt;br /&gt;(input.GamePads[0].ThumbSticks.Right.X &lt; 0))&lt;br /&gt;{&lt;br /&gt;cameraYaw += (spinRate * timeDelta);&lt;br /&gt;}&lt;br /&gt;if (input.KeyboardState.IsKeyDown(Keys.Right) ||&lt;br /&gt;(input.GamePads[0].ThumbSticks.Right.X &gt; 0))&lt;br /&gt;{&lt;br /&gt;cameraYaw -= (spinRate * timeDelta);&lt;br /&gt;}&lt;br /&gt;The thumb stick x and y axis provide a float value between -1 and 1. A value of 0 means&lt;br /&gt;there is no movement. A value of -0.5 means the stick is pushed to the left halfway. A&lt;br /&gt;value of 0.9 would be the stick is pushed to the right 90 percent of the way.&lt;br /&gt;We did not change the keyboard code, we simply added another “or” condition to handle&lt;br /&gt;our controller. We can see it is very simple, as we only needed to check the&lt;br /&gt;ThumbSticks.Left property. We check the x axis of that joystick and if it is less than zero&lt;br /&gt;the user is pushing the stick to the left. We check to see if it is positive (user pushing to&lt;br /&gt;the right) in the second condition. We leave our cameraYaw variable to be set by our spin&lt;br /&gt;rate (taking into account our time delta). At this point, regardless if players are using the&lt;br /&gt;keyboard or the game pad they will get the same result from the game: The camera will&lt;br /&gt;rotate around the y axis. Compile and run the program to try it out. We can also try the&lt;br /&gt;game on the Xbox 360 because we have hooked up our game pad code.&lt;br /&gt;At this point we know how to get access to any of the buttons (they are treated the same&lt;br /&gt;way as the Back button) and either thumb stick but we have not discussed the D-pad yet.&lt;br /&gt;96 CHAPTER 5 Input Devices and Cameras&lt;br /&gt;The D-pad is actually treated like buttons. If we also wanted to allow the player to rotate&lt;br /&gt;the camera left or right by using the D-pad, we simply need to add the following as part&lt;br /&gt;of our condition:&lt;br /&gt;gamePadState.DPad.Left == ButtonState.Pressed&lt;br /&gt;Add that condition along with a check for the right D-Pad being pressed to our code.&lt;br /&gt;Compile and run the code again and make sure that the demo allows us to look left or&lt;br /&gt;right by using the keyboard, thumb stick, and D-pad. The code should now look like the&lt;br /&gt;following:&lt;br /&gt;if (keyboardState.IsKeyDown(Keys.Left) ||&lt;br /&gt;(gamePadState.ThumbSticks.Right.X &lt; 0) ||&lt;br /&gt;(gamePadState.DPad.Left == ButtonState.Pressed))&lt;br /&gt;{&lt;br /&gt;cameraYaw += spinRate;&lt;br /&gt;}&lt;br /&gt;if (keyboardState.IsKeyDown(Keys.Right) ||&lt;br /&gt;(gamePadState.ThumbSticks.Right.X &gt; 0) ||&lt;br /&gt;(gamePadState.DPad.Right == ButtonState.Pressed))&lt;br /&gt;{&lt;br /&gt;cameraYaw -= spinRate;&lt;br /&gt;}&lt;br /&gt;The shoulder buttons are just that—buttons—and we know how to handle those already.&lt;br /&gt;We can determine when we press down on the left or right thumb stick because those are&lt;br /&gt;also considered buttons. However, the final item we discuss regarding our game pad&lt;br /&gt;controller is the triggers. Now, a good use of our triggers for this demo would be to turn&lt;br /&gt;on vibration!&lt;br /&gt;Before we actually determine how to use the triggers, we can look at another property of&lt;br /&gt;the game pad state we have access to and that is if the controller is actually connected or&lt;br /&gt;not. We can check this by getting the value of the IsConnected property.&lt;br /&gt;The trigger values return a float between 0 and 1 to signify how much the trigger is&lt;br /&gt;pressed (0 = not pressed; 1 = fully pressed). The Xbox 360 controller has two motors that&lt;br /&gt;create its vibration. The motor on the left is a low-frequency motor whereas the motor on&lt;br /&gt;the right is a high-frequency motor. We can set the values on both motors in the same&lt;br /&gt;method call. We do this by calling the GamePad.SetVibration method. Because this is just&lt;br /&gt;something we are doing for our demo and not really a part of the library, we will put this&lt;br /&gt;code in our Game1.cs file inside the Update method:&lt;br /&gt;if (input.GamePads[0].IsConnected)&lt;br /&gt;{&lt;br /&gt;GamePad.SetVibration(PlayerIndex.One, input.GamePads[0].Triggers.Left,&lt;br /&gt;input.GamePads[0].Triggers.Right);&lt;br /&gt;}&lt;br /&gt;Working with Input Devices 97&lt;br /&gt;5&lt;br /&gt;The first thing we are doing with this new code is checking to see if the game pad is actually&lt;br /&gt;connected. If it is connected then we set the vibration of both the left and right&lt;br /&gt;motors based on how much the left and right triggers are being pressed. We are calling&lt;br /&gt;the GamePad’s static SetVibration method. There is currently no benefit in wrapping&lt;br /&gt;that into a method inside of our input handler.&lt;br /&gt;We can also change the information being displayed in our window title bar to include&lt;br /&gt;the left and right motor values. This can help you determine what values you should use&lt;br /&gt;as you implement vibration in your games! The following is the code to accomplish that&lt;br /&gt;task:&lt;br /&gt;this.Window.Title = “left: “ +&lt;br /&gt;input.GamePads[0].Triggers.Left.ToString() + “; right: “ +&lt;br /&gt;input.GamePads[0].Triggers.Right.ToString();&lt;br /&gt;Go ahead and add this debug line inside of the IsConnected condition and compile and&lt;br /&gt;run the code to check the progress. We will no longer be able to see our frame rate with&lt;br /&gt;this code so we could just comment out the fps object until we are ready to actually&lt;br /&gt;check on our performance.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-3690563515209469955?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/3690563515209469955/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=3690563515209469955' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/3690563515209469955'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/3690563515209469955'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/working-with-gamepad-devices_03.html' title='Working with gamepad Devices'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-6296969104131585161</id><published>2008-04-03T21:40:00.001-07:00</published><updated>2008-04-03T21:40:28.005-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='device'/><category scheme='http://www.blogger.com/atom/ns#' term='keyboard'/><category scheme='http://www.blogger.com/atom/ns#' term='input'/><title type='text'>Working with keyboard Devices</title><content type='html'>We will be populating the stub we created for handling our input. We are going to create&lt;br /&gt;a stationary camera and a first person. Both of these cameras will need to respond to user&lt;br /&gt;input. We need to learn how to handle input devices and utilize them to move our&lt;br /&gt;camera and fully see the worlds we create.&lt;br /&gt;Keyboard&lt;br /&gt;The first input device we will talk about is the keyboard. XNA provides us with helper&lt;br /&gt;classes that allow us to easily determine the state of our input devices. We determine the&lt;br /&gt;state of our keyboard by declaring a variable to store our keyboard state and then calling&lt;br /&gt;the GetState method on the Keyboard helper object. We can then query that variable to&lt;br /&gt;determine which key (or keys) is being pressed or released. We can start by adding a&lt;br /&gt;private member field to store our keyboard state. We do this via the following code inside&lt;br /&gt;of our InputHandler game component:&lt;br /&gt;private KeyboardState keyboardState;&lt;br /&gt;Then we can find the Update method that was stubbed out for us when the InputHandler&lt;br /&gt;game component was created.&lt;br /&gt;keyboardState = Keyboard.GetState();&lt;br /&gt;if (keyboardState.IsKeyDown(Keys.Escape))&lt;br /&gt;Game.Exit();&lt;br /&gt;We can put this at the very beginning of the Update method. We are simply storing the&lt;br /&gt;state of the keyboard and then checking to see if the Escape key was pressed. If so, we&lt;br /&gt;simply exit the program. It doesn’t get much simpler than that! So now when we run the&lt;br /&gt;program we can exit by pressing the Escape key (instead of having to close the window&lt;br /&gt;with our mouse).&lt;br /&gt;Although being able to exit our game easily is important, we still haven’t done anything&lt;br /&gt;exciting. Let’s set up our camera so we swivel back and forth if the left or right keys are&lt;br /&gt;pressed. To do this we need to add and initialize a new private member field called&lt;br /&gt;cameraReference inside of our Camera game component:&lt;br /&gt;private Vector3 cameraReference = new Vector3(0.0f, 0.0f, -1.0f);&lt;br /&gt;This camera reference direction will not change throughout the game, but we will be&lt;br /&gt;passing it in as a reference so we cannot declare it as a readonly variable. Typically this&lt;br /&gt;value will either be (0,0,1) or (0,0,-1). We chose to have a negative z value so we can&lt;br /&gt;continue to have our camera face the same way.&lt;br /&gt;Now that we have our camera reference direction set up, we need to apply any movement&lt;br /&gt;and rotation to our view of the world. So if the player wants to look left and right we can&lt;br /&gt;adjust our view matrix accordingly so that our view of the world is from a certain angle.&lt;br /&gt;To look left and right we need to rotate around our y axis. We can add the following code&lt;br /&gt;to our Update method right before our call out to the base object’s Update method (we are&lt;br /&gt;still in our Camera class):&lt;br /&gt;Working with Input Devices 91&lt;br /&gt;5&lt;br /&gt;Matrix rotationMatrix;&lt;br /&gt;Matrix.CreateRotationY(MathHelper.ToRadians(cameraYaw), out rotationMatrix);&lt;br /&gt;// Create a vector pointing the direction the camera is facing.&lt;br /&gt;Vector3 transformedReference;&lt;br /&gt;Vector3.Transform(ref cameraReference, ref rotationMatrix,&lt;br /&gt;out transformedReference);&lt;br /&gt;// Calculate the position the camera is looking at.&lt;br /&gt;Vector3.Add(ref cameraPosition, ref transformedReference, out cameraTarget);&lt;br /&gt;Matrix.CreateLookAt(ref cameraPosition, ref cameraTarget, ref cameraUpVector,&lt;br /&gt;out view);&lt;br /&gt;Because we know we will be rotating, we will create a matrix to hold our rotation. With a&lt;br /&gt;helper function from XNA we will create a matrix with the appropriate values to rotate&lt;br /&gt;our camera on the y axis by a certain number of degrees. We are storing that value in a&lt;br /&gt;variable that we will set with our input devices. We will see how we set that value with&lt;br /&gt;our keyboard soon. Once we have our matrix with all of the translations, scaling, and&lt;br /&gt;rotations that we need (in this case we are only rotating) we can create a transform vector&lt;br /&gt;that will allow us to change the target of the camera. We get this transformed vector by&lt;br /&gt;using another XNA helper method, Vector3.Transform. We then add the transformed&lt;br /&gt;camera reference to our camera position, which will give us our new camera target. To do&lt;br /&gt;this, we could have used the plus (+) operator like the following code:&lt;br /&gt;cameraTarget = cameraPosition + transformedReference;&lt;br /&gt;However, it is much more efficient to use the built-in static Add method of the Vector3&lt;br /&gt;struct because it allows us to pass our vectors by reference instead of having to copy the&lt;br /&gt;values to memory. Finally, we reset our view with our new camera target. We also need to&lt;br /&gt;set the following private member field that we used in the code:&lt;br /&gt;private float cameraYaw = 0.0f;&lt;br /&gt;Now we are to the point where we can compile the code, but our newly added code does&lt;br /&gt;not do anything for us. This is because we are never changing our rotation angle. It stays&lt;br /&gt;at 0 on every frame. Let’s change that now with our keyboard. Inside of our InputHandler&lt;br /&gt;class, we need to update our IInputHandler interface to expose the keyboard state we&lt;br /&gt;retrieved earlier. Let’s add the following code inside of our interface:&lt;br /&gt;KeyboardState KeyboardState { get; }&lt;br /&gt;Now, we need to implement that property inside of the class. An easy way to do this is to&lt;br /&gt;right-click IInputHandler where we derived from it and select Implement Interface. We&lt;br /&gt;will be doing this a couple of times and each time it will create a region so we will have&lt;br /&gt;to clean up the code and remove the extra regions the IDE provides for us. Now we need&lt;br /&gt;to change the get value to retrieve our internal keyboardState value as follows:&lt;br /&gt;92 CHAPTER 5 Input Devices and Cameras&lt;br /&gt;public KeyboardState KeyboardState&lt;br /&gt;{&lt;br /&gt;get { return(keyboardState); }&lt;br /&gt;}&lt;br /&gt;Now that we have exposed our keyboard state we can utilize it inside of our Camera&lt;br /&gt;object. We need to add the following code to our Update method right above the previous&lt;br /&gt;code inside of our camera object:&lt;br /&gt;if (input.KeyboardState.IsKeyDown(Keys.Left))&lt;br /&gt;cameraYaw += spinRate;&lt;br /&gt;if (input.KeyboardState.IsKeyDown(Keys.Right))&lt;br /&gt;cameraYaw -= spinRate;&lt;br /&gt;if (cameraYaw &gt; 360)&lt;br /&gt;cameraYaw -= 360;&lt;br /&gt;else if (cameraYaw &lt; 0)&lt;br /&gt;cameraYaw += 360;&lt;br /&gt;We also need to make sure camera is using the XNA Framework’s Input namespace&lt;br /&gt;because we are accessing the Keys enumeration:&lt;br /&gt;using Microsoft.Xna.Framework.Input;&lt;br /&gt;Finally, we add this constant to the top of our camera class:&lt;br /&gt;private const float spinRate = 2.0f;&lt;br /&gt;In our update code we utilized the current keyboard state we already captured and&lt;br /&gt;checked to see if either the left arrow or right arrow on the keyboard was pressed. If the&lt;br /&gt;player wants to rotate to the left then we add our spin rate constant to our current&lt;br /&gt;camera yaw angle. (Yaw, pitch, and roll are terms borrowed from flight dynamics. Because&lt;br /&gt;we are using a right-handed coordinate system, this means that yaw is rotation around&lt;br /&gt;the y axis, pitch is rotation around the x axis, and roll is rotation around the z axis.) If&lt;br /&gt;the player wants to rotate to the right then we subtract our spin rate constant from our&lt;br /&gt;current camera yaw angle. Finally we just check to make sure that we do not have an&lt;br /&gt;invalid rotation angle.&lt;br /&gt;There is one last thing we need to do before we can run our code again. We need to actually&lt;br /&gt;add our input handler game component to our game’s collection of components. We&lt;br /&gt;can declare our member field as follows:&lt;br /&gt;private InputHandler input;&lt;br /&gt;Now we can actually initialize that variable and add it to the collection inside of our&lt;br /&gt;constructor with this code:&lt;br /&gt;input = new InputHandler(this);&lt;br /&gt;Components.Add(input);&lt;br /&gt;Working with Input Devices 93&lt;br /&gt;5&lt;br /&gt;We can compile and run the code and move knowing that our left and right arrows rotate&lt;br /&gt;the camera. When running we can see that our objects are just flying by. It almost seems&lt;br /&gt;they are blinking we are turning so fast. This is because we are calling our Update statement&lt;br /&gt;as fast as possible. We can modify the game code where we are initializing our fps&lt;br /&gt;variable to use a fixed time step:&lt;br /&gt;fps = new FPS(this, false, true);&lt;br /&gt;For the preceding code to work we need to add another constructor to our FPS code. We&lt;br /&gt;are doing this is so we don’t need to actually pass in our target elapsed time value if we&lt;br /&gt;want it to be the default.&lt;br /&gt;public FPS(Game game, bool synchWithVerticalRetrace, bool isFixedTimeStep)&lt;br /&gt;: this(game, synchWithVerticalRetrace, isFixedTimeStep,&lt;br /&gt;game.TargetElapsedTime) { }&lt;br /&gt;Now when we run the code we can see the objects move by at a consistent and slower&lt;br /&gt;rate. This is because the Update method is now only getting called 60 times a second&lt;br /&gt;instead of whatever rate our machine was running at.&lt;br /&gt;We will notice, however, that as it renders the rectangles that our screen is “choppy.” The&lt;br /&gt;reason is that we are not letting XNA only draw during our monitor’s vertical refresh. We&lt;br /&gt;could do this by setting our second parameter to true and we would see the screen rotate&lt;br /&gt;at a nice even pace with the screen drawing nicely. However, a better way to handle this&lt;br /&gt;is by utilizing the elapsed time between calls to our methods. We need to retrieve the&lt;br /&gt;elapsed time since the last time our Update method was called and then multiply our&lt;br /&gt;spinRate by this delta of the time between calls. We will change the camera code snippet&lt;br /&gt;to match the following:&lt;br /&gt;float timeDelta = (float)gameTime.ElapsedGameTime.TotalSeconds;&lt;br /&gt;if (input.KeyboardState.IsKeyDown(Keys.Left))&lt;br /&gt;cameraYaw += (spinRate * timeDelta);&lt;br /&gt;if (input.KeyboardState.IsKeyDown(Keys.Right))&lt;br /&gt;cameraYaw -= (spinRate * timeDelta);&lt;br /&gt;We can modify our game code to call the default constructor again:&lt;br /&gt;fps = new FPS(this);&lt;br /&gt;Now we are just creeping along. This is because our spin rate is so low. We had it low&lt;br /&gt;because we were relying on the update method to be called 60 times per frame, so we&lt;br /&gt;were basically rotating our camera 120 degrees per second. To get the same effect we&lt;br /&gt;simply set our spinRate to 120. The reason is we are now multiplying it by the time&lt;br /&gt;difference between calls. At this point we can safely set our units and know they will be&lt;br /&gt;used on a per-second basis. Now that we have our spinRate utilizing the delta of the time&lt;br /&gt;between calls we are safe to run at any frame rate and have our objects drawn correctly&lt;br /&gt;based on the amount of time that has elapsed.&lt;br /&gt;94 CHAPTER 5 Input Devices and Cameras&lt;br /&gt;We can have it always run at 60 fps in release mode and run as fast as possible in debug&lt;br /&gt;mode by modifying our game code as follows:&lt;br /&gt;#if DEBUG&lt;br /&gt;fps = new FPS(this);&lt;br /&gt;#else&lt;br /&gt;fps = new FPS(this, true, false);&lt;br /&gt;#endif&lt;br /&gt;This allows us to run as fast as we can in debug mode while consistently moving our&lt;br /&gt;objects no matter the frame rate. It allows us to force XNA to only update the screen&lt;br /&gt;during the monitor’s vertical retrace, which would drop us to 60 fps or whatever rate the&lt;br /&gt;monitor is refreshing at.&lt;br /&gt;Making a game update itself consistently regardless of the frame rate can make the game&lt;br /&gt;more complex. We need to calculate the elapsed time (time delta) since the last frame and&lt;br /&gt;use that value in all of our calculations. With the fixed step mode that XNA provides we&lt;br /&gt;could cut down on development time and rely on the fact that the update code will be&lt;br /&gt;called 60 times a second. This is not sufficient if we are writing a library that can be&lt;br /&gt;plugged into games, as those games might not run at a consistent frame rate.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-6296969104131585161?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/6296969104131585161/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=6296969104131585161' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/6296969104131585161'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/6296969104131585161'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/working-with-keyboard-devices_03.html' title='Working with keyboard Devices'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-3818922218524816037</id><published>2008-04-03T21:35:00.000-07:00</published><updated>2008-04-03T21:36:22.069-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='texture'/><category scheme='http://www.blogger.com/atom/ns#' term='textures'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>Textures</title><content type='html'>We have a triangle finally drawn on the screen, but it does not look particularly&lt;br /&gt;good. We can fix that by adding a texture. Copy the texture from the&lt;br /&gt;Chapter4\XNADemo\XNADemo folder (texture.jpg) and paste that into our project.&lt;br /&gt;This invokes the XNA Content Pipeline, which we discuss in Part III, “Content Pipeline”.&lt;br /&gt;For now, we just need to know that it makes it available as loadable content complete&lt;br /&gt;with a name by which we can access it. The asset will get the name “texture” (because that&lt;br /&gt;is the name of the file). We need to declare a private member field to store our texture:&lt;br /&gt;68 CHAPTER 4 Creating 3D Objects&lt;br /&gt;private Texture2D texture;&lt;br /&gt;We define our texture as a Texture2D object. This is another class that XNA provides for&lt;br /&gt;us. Texture2D inherits from the Texture class, which allows us to manipulate a texture&lt;br /&gt;resource. Now we need to actually load our texture into that variable. We do this in the&lt;br /&gt;LoadGraphicsContent method. Inside of the loadAllContent condition, add this line of&lt;br /&gt;code:&lt;br /&gt;texture = content.Load&lt;Texture2D&gt;(“texture”);&lt;br /&gt;Now we have our texture added to our project and loaded into a variable (with very little&lt;br /&gt;code), but we have yet to associate that texture to the effect that we used to draw the&lt;br /&gt;triangle. We will do that now by adding the following two lines of code right before our&lt;br /&gt;call to effect.Begin inside of our Draw method:&lt;br /&gt;effect.TextureEnabled = true;&lt;br /&gt;effect.Texture = texture;&lt;br /&gt;This simply tells the effect we are using that we want to use textures, and then we actually&lt;br /&gt;assign the texture to our effect. It is really that simple. Go ahead and compile and run&lt;br /&gt;the code to see our nicely textured triangle!&lt;br /&gt;&lt;br /&gt;Index Buffers&lt;br /&gt;&lt;br /&gt;We have covered a lot of ground so far, but we aren’t done yet. We want to create a&lt;br /&gt;rectangle on the screen and to do this we need another triangle. So that means we need&lt;br /&gt;three more vertices, or do we? Actually, we only need one more vertex to create our&lt;br /&gt;square because the second triangle we need to complete the square shares two of our existing&lt;br /&gt;points already. Feel free to review a couple of sections earlier where we talked about&lt;br /&gt;vertex buffers. We set up three points to make the triangle we just saw. To use the code as&lt;br /&gt;is we would need to create another three points, but two of those points are redundant&lt;br /&gt;and the amount of data it takes to represent the VertexPositionNormalTexture struct is&lt;br /&gt;not minimal, so we do not want to duplicate all of that data if we do not need to.&lt;br /&gt;Fortunately, we do not. XNA provides us with index buffers. Index buffers simply store&lt;br /&gt;indices that correspond to our vertex buffer. So to resolve our current dilemma of not&lt;br /&gt;wanting to duplicate our heavy vertex data we will instead duplicate our index data, which&lt;br /&gt;is much smaller. Our vertex buffer will only store four points (instead of six) and our index&lt;br /&gt;buffer will store six indices that will correspond to our vertices in the order we want them&lt;br /&gt;to be drawn. We need to increase our vertex array to hold four values instead of three.&lt;br /&gt;Make the following change:&lt;br /&gt;vertices = new VertexPositionNormalTexture[4];&lt;br /&gt;An index buffer simply describes the order in which we want the vertices in our vertex&lt;br /&gt;buffer to be drawn in our scene.&lt;br /&gt;Find the InitializeVertices method in our code and add the last point we need for our&lt;br /&gt;rectangle. Try to do this before looking at the following code.&lt;br /&gt;Index Buffers 69&lt;br /&gt;4&lt;br /&gt;//top right&lt;br /&gt;position = new Vector3(1, 1, 0);&lt;br /&gt;textureCoordinates = new Vector2(1, 0);&lt;br /&gt;vertices[3] = new VertexPositionNormalTexture(position, Vector3.Forward,&lt;br /&gt;textureCoordinates);&lt;br /&gt;As you were writing the code, I imagine you were wondering about the texture coordinates&lt;br /&gt;for the points. We finally talked about textures, but not really how we mapped the&lt;br /&gt;texture to the vertices we created. We will take a moment and do that now before we&lt;br /&gt;continue our understanding of index buffers.&lt;br /&gt;Texture coordinates start at the top left at (0,0) and end at the bottom right at (1,1). The&lt;br /&gt;bottom left texture coordinate is (0,1) and the top right is (1,0). Take a look at Figure 4.4&lt;br /&gt;to see an example.&lt;br /&gt;&lt;br /&gt;If we wanted to map a vertex to the bottom center pixel of a texture, what should the&lt;br /&gt;values be? The horizontal axis is our x axis and the vertical axis is our y axis. We know we&lt;br /&gt;need a 1 in our y coordinate to get to the very bottom of the texture. To get to the middle&lt;br /&gt;of that bottom row, we would need to take the value in between 0 and 1, which is 0.5. So&lt;br /&gt;if we wanted to map a vertex to the bottom center pixel of a texture, we would map it at&lt;br /&gt;(0.5, 1). Back to our demo: Because the vertex we just added was the top right point of&lt;br /&gt;the rectangle, the texture coordinate we assigned to it was (1,0).&lt;br /&gt;Now that we have a better understanding of why our texture mapped to our triangle&lt;br /&gt;correctly, we can get back to our index buffer. We have added a vertex to our code and&lt;br /&gt;now we need to create an index buffer to reference these four points. We need to create&lt;br /&gt;another private member field called indices:&lt;br /&gt;private short[] indices;&lt;br /&gt;Notice that we declared this as an array of short. We could have used int, but short takes&lt;br /&gt;up less room and we aren’t going to have more than 65,535 indices in this demo. The&lt;br /&gt;next thing we need to do is actually create our method that will initialize our indices.&lt;br /&gt;We will name this InitializeIndices and we will call this method from inside our&lt;br /&gt;LoadGraphicsContent method right after we make the call to InitializeVertices. Make&lt;br /&gt;sure that the vertex was added right before we initialize our vertex buffer and after we&lt;br /&gt;created all of the other vertices. This way the code for InitializeIndices shown next&lt;br /&gt;will work for us. It assumes the latest addition to our list of vertices is at the bottom of&lt;br /&gt;the list.&lt;br /&gt;private void InitializeIndices()&lt;br /&gt;{&lt;br /&gt;//6 vertices make up 2 triangles which make up our rectangle&lt;br /&gt;indices = new short[6];&lt;br /&gt;//triangle 1 (bottom portion)&lt;br /&gt;indices[0] = 0; // top left&lt;br /&gt;indices[1] = 1; // bottom right&lt;br /&gt;indices[2] = 2; // bottom left&lt;br /&gt;//triangle 2 (top portion)&lt;br /&gt;indices[3] = 0; // top left&lt;br /&gt;indices[4] = 3; // top right&lt;br /&gt;indices[5] = 1; // bottom right&lt;br /&gt;}&lt;br /&gt;In this method we know we are going to create two triangles (with three points each) so&lt;br /&gt;we create enough space to hold all six indices. We then populate our indices. We took&lt;br /&gt;care to add our vertices in a clockwise order when adding them to the vertex list, so we&lt;br /&gt;can simply set our first three indices to 0, 1, and 2. The second triangle, however, needs a&lt;br /&gt;little more thought. We know we have to add these in clockwise order, so we can start&lt;br /&gt;with any vertex and work our way around. Let us start with the top left vertex (the first&lt;br /&gt;vertex we added to our list—index of 0). That means we need to set our next index to be&lt;br /&gt;the top right vertex, which is the one we just added to the end of the list. We set that&lt;br /&gt;index to 3. Finally, we set the last point to the bottom right vertex, which was added to&lt;br /&gt;the vertex buffer second and has the index of 1.&lt;br /&gt;Now we have our vertices created, complete with textured coordinates and position and&lt;br /&gt;even normals. We have our indices set up to use the vertex buffer in a way where we did&lt;br /&gt;not have to duplicate any of the complex vertex data. We further saved memory by using&lt;br /&gt;short instead of int because we will only have a few indices we need to store to represent&lt;br /&gt;our 3D object (our rectangle). Also, some older graphic cards do not support 32-bit (int)&lt;br /&gt;index buffers. The only thing left for us to do is to actually modify our code that draws&lt;br /&gt;the primitive to tell it we are now using an index buffer. To do that, find the Draw method&lt;br /&gt;and locate the call to DrawUserPrimitives. We will want to replace that line with the&lt;br /&gt;following line:&lt;br /&gt;graphics.GraphicsDevice.DrawUserIndexedPrimitives(&lt;br /&gt;PrimitiveType.TriangleList, vertices, 0, vertices.Length,&lt;br /&gt;indices, 0, indices.Length / 3);&lt;br /&gt;Index Buffers 71&lt;br /&gt;4&lt;br /&gt;Notice that we changed the method we are calling on the graphics device. We are now&lt;br /&gt;passing in both vertex and index data. Let’s break down the parameters we are passing in.&lt;br /&gt;We still pass in a triangle array as the first parameter and our array of vertices as the&lt;br /&gt;second parameter and we are leaving our vertex offset at 0. The next parameter is new&lt;br /&gt;and simply needs the number of vertices that is in our vertex array. The fifth parameter is&lt;br /&gt;our array of indices (this method has an override that accepts an array of int as well). The&lt;br /&gt;sixth parameter is the offset we want for our index buffer. We want to use all of the&lt;br /&gt;indices so we passed in 0. The final parameter, primitive count, is the same as the final&lt;br /&gt;parameter in the method we just replaced. Because we only have four vertices we needed&lt;br /&gt;to change that to our index array. Our indices array has six references to vertices in it and&lt;br /&gt;we take that value and divide it by three to get the number of triangles that are in our&lt;br /&gt;triangle list. When we compile and run the code we should see a rectangle that was&lt;br /&gt;created with our modified vertex buffer and our new index buffer!&lt;br /&gt;As an exercise, modify the points in our vertex to have the rectangle slanted into the&lt;br /&gt;screen. This will require modifying a couple of our z values from 0 to something else.&lt;br /&gt;Give it a try!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-3818922218524816037?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/3818922218524816037/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=3818922218524816037' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/3818922218524816037'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/3818922218524816037'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/textures_03.html' title='Textures'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-6529134750541924950</id><published>2008-04-03T21:34:00.000-07:00</published><updated>2008-04-03T21:35:35.941-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='effect'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>Effects</title><content type='html'>Effects are used to get anything in our XNA 3D game to actually show up on the screen.&lt;br /&gt;They handle things like lights, textures, and even position of the points. We will talk&lt;br /&gt;about effects extensively in Part V, “High Level Shading Language (HLSL).” For now, we&lt;br /&gt;can utilize the BasicEffect class that XNA provides. This keeps us from having to actually&lt;br /&gt;create an effect file so we can get started quickly.&lt;br /&gt;The first thing to notice is that we create a new variable to hold our effect. We do this by&lt;br /&gt;passing in the graphics device as our first parameter and we are passing in null as the&lt;br /&gt;effect pool because we are only using one effect and don’t need a pool to share among&lt;br /&gt;66 CHAPTER 4 Creating 3D Objects&lt;br /&gt;multiple effects. After creating our effect, we want to set some of the properties so we can&lt;br /&gt;use it. Notice we set the world, view, and projection matrices for the effect as well as&lt;br /&gt;telling the effect to turn on the default lighting. We discuss lighting in detail in the HLSL&lt;br /&gt;part of our book, but for now, this will light up the 3D scene so we can see our objects.&lt;br /&gt;TIP&lt;br /&gt;It is a good idea to leave the background color set to Color.CornflowerBlue or some&lt;br /&gt;other nonblack color. The reason for this is if the lights are not set up correctly, the&lt;br /&gt;object will render in black (no light is shining on it). So if the background color is&lt;br /&gt;black, we might think that the object didn’t render at all.&lt;br /&gt;Now back to our code. Notice that we call the Begin method on our effect and we also&lt;br /&gt;call the End method. Anything we draw on the screen in between these two calls will&lt;br /&gt;have that effect applied to them. The next section of code is our foreach loop. This loop&lt;br /&gt;iterates through all of the passes of our effect. Effects will have one or more techniques. A&lt;br /&gt;technique will have one or more passes. For this basic effect, we have only one technique&lt;br /&gt;and one pass. We will learn about techniques and passes in more detail in Part V. At this&lt;br /&gt;point we have another begin and end pair, but this time it is for the pass of the current&lt;br /&gt;(only) technique in our effect. Inside of this pass is where we finally get to draw our triangle&lt;br /&gt;onto the screen. This is done using the DrawUserPrimitives method in the graphics&lt;br /&gt;device object:&lt;br /&gt;graphics.GraphicsDevice.DrawUserPrimitives(&lt;br /&gt;PrimitiveType.TriangleList, vertices, 0, vertices.Length / 3);&lt;br /&gt;We are passing in the type of primitive we will be rendering. The primitives we are&lt;br /&gt;drawing are triangles so we are going to pass in a triangle list. This is the most common&lt;br /&gt;primitive type used in modern games. Refer to Table 4.1 for a list of different primitive&lt;br /&gt;types and how they can be used. The second parameter we pass in is the actual vertex&lt;br /&gt;data we created in our InitializeVertices method. The third parameter is the offset of&lt;br /&gt;the point data where we want to start drawing—in our case we want to start with the first&lt;br /&gt;point, so that is 0. Finally, we need to pass in the number of triangles we are drawing on&lt;br /&gt;the screen. We can calculate this by taking the number of points we have stored and&lt;br /&gt;dividing it by 3 (as there are 3 points in a triangle). For our example, this will return one&lt;br /&gt;triangle. If we compile and run the code at this point we should see a triangle drawn on&lt;br /&gt;our screen. It is not very pretty, as it is a dull shade of gray, but it is a triangle nonetheless.&lt;br /&gt;To see a screen shot, refer to Figure 4.3.&lt;br /&gt;Effects 67&lt;br /&gt;4&lt;br /&gt;Member Name Description&lt;br /&gt;LineList Renders the vertices as a list of isolated straight-line segments.&lt;br /&gt;LineStrip Renders the vertices as a single polyline.&lt;br /&gt;PointList Renders the vertices as a collection of isolated points. This value is&lt;br /&gt;unsupported for indexed primitives.&lt;br /&gt;TriangleFan Renders the vertices as a triangle fan.&lt;br /&gt;TriangleList Renders the specified vertices as a sequence of isolated triangles. Each&lt;br /&gt;group of three vertices defines a separate triangle. Back-face culling is&lt;br /&gt;affected by the current winding-order render state.&lt;br /&gt;TriangleStrip Renders the vertices as a triangle strip. The back-face culling flag is&lt;br /&gt;flipped automatically on even-numbered triangles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-6529134750541924950?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/6529134750541924950/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=6529134750541924950' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/6529134750541924950'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/6529134750541924950'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/effects.html' title='Effects'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-268048725373859159</id><published>2008-04-03T21:33:00.000-07:00</published><updated>2008-04-03T21:34:16.243-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='camera'/><category scheme='http://www.blogger.com/atom/ns#' term='create'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>Creating a Camera</title><content type='html'>That is enough theory for a bit. We are going to create a camera so we can view our&lt;br /&gt;world. Now we can create a new Windows game project to get started with this section.&lt;br /&gt;We can call this project XNADemo. To begin, we will need to create the following private&lt;br /&gt;member fields:&lt;br /&gt;private Matrix projection;&lt;br /&gt;private Matrix view;&lt;br /&gt;private Matrix world;&lt;br /&gt;We will then need to add a call to InitializeCamera in the beginning of our&lt;br /&gt;LoadGraphicsContent method. The InitializeCamera method will have no return&lt;br /&gt;value. We will begin to populate the method, which can be marked as private, in the next&lt;br /&gt;three points.&lt;br /&gt;Projection&lt;br /&gt;The Matrix struct has a lot of helper functions built in that we can utilize. The&lt;br /&gt;Matrix.CreatePerspectiveFieldOfView is the method we want to look at now.&lt;br /&gt;float aspectRatio = (float)graphics.GraphicsDevice.Viewport.Width /&lt;br /&gt;(float)graphics.GraphicsDevice.Viewport.Height;&lt;br /&gt;Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, aspectRatio,&lt;br /&gt;0.0001f, 1000.0f, out projection);&lt;br /&gt;First we set up a local variable aspectRatio. This is to store, you guessed it, the aspect&lt;br /&gt;ratio of our screen. For the Xbox 360 the aspect ratio of the back buffer will determine&lt;br /&gt;how the game is displayed on the gamer’s TV. If we develop with a widescreen aspect ratio&lt;br /&gt;and the user has a standard TV, the game will have a letterbox look to it. Conversely, if we&lt;br /&gt;develop with a standard aspect ratio and the user has a wide screen, the Xbox 360 will&lt;br /&gt;stretch the display. To avoid this we should account for both situations and then adjust&lt;br /&gt;the value of our aspect ratio variable to the default values of the viewport of the graphics&lt;br /&gt;device like in the preceding code. If we needed to query the default value to which the&lt;br /&gt;gamer had his or her Xbox 360 set, we can gather that information by querying the&lt;br /&gt;DisplayMode property of the graphics device during or after the Initialization method&lt;br /&gt;is called by the framework.&lt;br /&gt;Creating a Camera 61&lt;br /&gt;4&lt;br /&gt;However, if we want to force a widescreen aspect ratio on the Xbox 360 we could set the&lt;br /&gt;PreferredBackBufferWidth and PreferredBackBufferHeight properties on the graphics&lt;br /&gt;object right after creating it. Many gamers do not care for the black bars, so we should use&lt;br /&gt;this with caution. To force a widescreen aspect ratio on Windows is a little more complicated,&lt;br /&gt;but the XNA Game Studio Express documentation has a great “How to” page&lt;br /&gt;explaining how to do it. Once in the documentation, you can find “How to: Restrict&lt;br /&gt;Graphics Devices to Widescreen Aspect Ratios in Full Screen” under the Application&lt;br /&gt;Model in the Programming Guide.&lt;br /&gt;Second, we create our field of view. The first parameter we pass in is 45 degrees. We could&lt;br /&gt;have used MathHelper.ToRadians(45.0f) but there is no need to do the math because the&lt;br /&gt;MathHelper class already has the value as a constant. The second parameter is the aspect&lt;br /&gt;ratio, which we already calculated. The third and fourth parameters are our near and far&lt;br /&gt;clipping planes, respectively. The plane values represent how far the plane is from our&lt;br /&gt;camera. It means anything past the far clipping plane will not be drawn onto the screen.&lt;br /&gt;It also means anything closer to us than the near clipping plane will not be drawn either.&lt;br /&gt;Only the points that fall in between those two planes and are within a 45-degree angle of&lt;br /&gt;where we are looking will be drawn on the screen. The last parameter is where we populate&lt;br /&gt;our projection matrix. This is an overloaded method. (One version actually returns&lt;br /&gt;the projection, but we will utilize the overload that has reference and out parameters, as&lt;br /&gt;they are faster because it doesn’t have to copy the value of the data.)&lt;br /&gt;View&lt;br /&gt;Now that we have our projection matrix set, we can set up our view matrix. To do this we&lt;br /&gt;are going to use another XNA matrix helper method. The Matrix.CreateLookAt method&lt;br /&gt;takes three parameters. Let’s create and initialize these private member fields now.&lt;br /&gt;private Vector3 cameraPosition = new Vector3(0.0f, 0.0f, 3.0f);&lt;br /&gt;private Vector3 cameraTarget = Vector3.Zero;&lt;br /&gt;private Vector3 cameraUpVector = Vector3.Up;&lt;br /&gt;Now we can actually call the CreateLookAt method inside of our InitializeCamera&lt;br /&gt;method. We should add the following code at the end of the method:&lt;br /&gt;Matrix.CreateLookAt(ref cameraPosition, ref cameraTarget,&lt;br /&gt;ref cameraUpVector, out view);&lt;br /&gt;The first parameter we pass in is our camera position. We are passing in the coordinates&lt;br /&gt;(0,0,3) for our camera position to start with, so our camera position will remain at the&lt;br /&gt;origin of the x and y axis, but it will move backward from the origin 3 units. The second&lt;br /&gt;parameter of the CreateLookAt method is the target of where we are aiming the camera.&lt;br /&gt;In this example, we are aiming the camera at the origin of the world Vector3.Zero&lt;br /&gt;(0,0,0). Finally, we pass in the camera’s up vector. For this we use the Up property on&lt;br /&gt;Vector3, which means (0,1,0). Notice we actually created a variable for this so we can pass&lt;br /&gt;it in by reference. This is also an overloaded method, and because we want this to be fast&lt;br /&gt;we will pass the variables in by reference instead of by value. Fortunately, we do not lose&lt;br /&gt;much readability with this performance gain.&lt;br /&gt;62 CHAPTER 4 Creating 3D Objects&lt;br /&gt;World&lt;br /&gt;At this point if we compiled and ran the demo we would still see the lovely blank cornflower&lt;br /&gt;blue screen because we have not set up our world matrix or put anything in the&lt;br /&gt;world to actually look at. Let’s fix that now.&lt;br /&gt;As we saw, the templates provide a lot of methods stubbed out for us. One of these very&lt;br /&gt;important methods is the Draw method. Find this method and add this line of code right&lt;br /&gt;below the TODO: Add your drawing code here comment:&lt;br /&gt;world = Matrix.Identity;&lt;br /&gt;This simply sets our world matrix to an identity matrix, which means that there is no&lt;br /&gt;scaling, no rotating, and no translating (movement). The identity matrix has a translation&lt;br /&gt;of (0,0,0) so this will effectively set our world matrix to the origin of the world.&lt;br /&gt;At this point we have our camera successfully set up but we have not actually drawn&lt;br /&gt;anything. We are going to correct that starting with the next section.&lt;br /&gt;Vertex Buffers&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3D objects are made up of triangles. Every object is one triangle or more. For example, a&lt;br /&gt;sphere is just made up of triangles; the more triangles, the more rounded the sphere is.&lt;br /&gt;Take a look at Figure 4.1 to see how this works. Now that we know that every 3D object&lt;br /&gt;we render is made up of triangles and that a triangle is simply three vertices in 3D space,&lt;br /&gt;we can use vertex buffers to store a list of 3D points. As the name implies, a vertex buffer&lt;br /&gt;is simply memory (a buffer) that holds a list of vertices.&lt;br /&gt;Vertex Buffers 63&lt;br /&gt;4&lt;br /&gt;FIGURE 4.1 All 3D objects are made up of triangles.&lt;br /&gt;XNA uses a right-handed coordinate system. This means that the x axis goes from left to&lt;br /&gt;right (left being negative and right being positive), the y axis goes up and down (down&lt;br /&gt;being negative and up being positive), and z goes forward and backward (forward being&lt;br /&gt;negative and backward being positive). We can visualize this by extending our right arm&lt;br /&gt;out to our right and positioning our hand like we are holding a gun. Now rotate our wrist&lt;br /&gt;so our palm is facing the sky. At this point our pointer finger should be pointing to the&lt;br /&gt;right (this is our x axis going in a positive direction to the right). Our thumb should be&lt;br /&gt;pointing behind us (this is our z axis going in a positive direction backward). Now, we&lt;br /&gt;uncurl our three fingers so they are pointing to the sky (this represents the y axis with a&lt;br /&gt;positive direction upward). Take a look at Figure 4.2 to help solidify how the right-handed&lt;br /&gt;coordinate system works.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now that we know what the positive direction is for each axis we are ready to start plotting&lt;br /&gt;our points. XNA uses counterclockwise culling. Culling is a performance measure&lt;br /&gt;graphic cards take to keep from rendering objects that are not facing the camera. XNA has&lt;br /&gt;three options for culling: CullClockwiseFace, CullCounterClockwiseFace, and None. The&lt;br /&gt;default culling mode for XNA is CullCounterClockwiseFace, so to see our objects we have&lt;br /&gt;to set up our points in the opposite order—clockwise.&lt;br /&gt;TIP&lt;br /&gt;It is helpful to use some graph paper (or regular notebook paper for that matter) to&lt;br /&gt;plot out points. Simply put points where we want them and make sure when we put&lt;br /&gt;them into the code, we do it in a clockwise order.&lt;br /&gt;Let’s plot some points. Ultimately, we want to make a square. We know that all 3D&lt;br /&gt;objects can be made with triangles and we can see that a square is made up of two triangles.&lt;br /&gt;We will position the first triangle at (-1,1,0); (1,-1,0); (-1,-1,0). That means the first&lt;br /&gt;point (-1,1,0) will be positioned on the x axis 1 unit to the left and it will be 1 unit up the&lt;br /&gt;y axis and will stay at the origin on the z axis. The code needed to set up these points is&lt;br /&gt;as follows:&lt;br /&gt;private void InitializeVertices()&lt;br /&gt;{&lt;br /&gt;Vector3 position;&lt;br /&gt;Vector2 textureCoordinates;&lt;br /&gt;vertices = new VertexPositionNormalTexture[3];&lt;br /&gt;//top left&lt;br /&gt;position = new Vector3(-1, 1, 0);&lt;br /&gt;textureCoordinates = new Vector2(0, 0);&lt;br /&gt;vertices[0] = new VertexPositionNormalTexture(position, Vector3.Forward,&lt;br /&gt;textureCoordinates);&lt;br /&gt;//bottom right&lt;br /&gt;position = new Vector3(1, -1, 0);&lt;br /&gt;textureCoordinates = new Vector2(1, 1);&lt;br /&gt;vertices[1] = new VertexPositionNormalTexture(position, Vector3.Forward,&lt;br /&gt;textureCoordinates);&lt;br /&gt;//bottom left&lt;br /&gt;position = new Vector3(-1, -1, 0);&lt;br /&gt;textureCoordinates = new Vector2(0, 1);&lt;br /&gt;vertices[2] = new VertexPositionNormalTexture(position, Vector3.Forward,&lt;br /&gt;textureCoordinates);&lt;br /&gt;}&lt;br /&gt;As we look at this function we can see three variables that have been created: vertex,&lt;br /&gt;position, and textureCoordinates. The vertex variable will store our vertex (point) data.&lt;br /&gt;XNA has different structs that describe the type of data a vertex will hold. In most cases&lt;br /&gt;for 3D games we will need to store the position, normal, and texture coordinates. We&lt;br /&gt;discuss normals later, but for now it is sufficient to know they let the graphics device&lt;br /&gt;know how to reflect light off of the face (triangle). The most important part of the vertex&lt;br /&gt;variable is the position of the point in 3D space. We saw earlier that XNA allows us to&lt;br /&gt;store that information in a Vector3 struct. We can either set the data in the constructor as&lt;br /&gt;we did in this code, or we can explicitly set its X, Y, and Z properties.&lt;br /&gt;We skip over explaining the texture coordinates momentarily, but notice it uses the&lt;br /&gt;Vector2 struct that XNA provides for us.We need to add the following private member&lt;br /&gt;field to our class that we have been using to store our vertices:&lt;br /&gt;private VertexPositionNormalTexture[] vertices;&lt;br /&gt;We need to call this method in our application. The appropriate place to call the&lt;br /&gt;InitializeVertices method is inside of the LoadGraphicsContent method.&lt;br /&gt;Vertex Buffers 65&lt;br /&gt;4&lt;br /&gt;If we compile and run our application now we still do not see anything on the screen.&lt;br /&gt;This is because we have not actually told the program to draw our triangle! We will want&lt;br /&gt;to find our Draw method and before the last call to the base class base.Draw(gameTime),&lt;br /&gt;we need to add the following code:&lt;br /&gt;graphics.GraphicsDevice.VertexDeclaration = new&lt;br /&gt;VertexDeclaration(graphics.GraphicsDevice,&lt;br /&gt;VertexPositionNormalTexture.VertexElements);&lt;br /&gt;BasicEffect effect = new BasicEffect(graphics.GraphicsDevice, null);&lt;br /&gt;world = Matrix.Identity;&lt;br /&gt;effect.World = world;&lt;br /&gt;effect.Projection = projection;&lt;br /&gt;effect.View = view;&lt;br /&gt;effect.EnableDefaultLighting();&lt;br /&gt;effect.Begin();&lt;br /&gt;foreach (EffectPass pass in effect.CurrentTechnique.Passes)&lt;br /&gt;{&lt;br /&gt;pass.Begin();&lt;br /&gt;graphics.GraphicsDevice.DrawUserPrimitives(&lt;br /&gt;PrimitiveType.TriangleList, vertices, 0,&lt;br /&gt;vertices.Length / 3);&lt;br /&gt;pass.End();&lt;br /&gt;}&lt;br /&gt;effect.End();&lt;br /&gt;You might think there is a lot of code here just to draw the points we have created on the&lt;br /&gt;screen. Well, there is, but it is all very straightforward and we can plow on through.&lt;br /&gt;Before we do, though, let’s take a minute and talk about effects.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-268048725373859159?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/268048725373859159/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=268048725373859159' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/268048725373859159'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/268048725373859159'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/creating-camera_03.html' title='Creating a Camera'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-3068434066523734256</id><published>2008-04-03T21:31:00.000-07:00</published><updated>2008-04-03T21:32:47.476-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='reloaded'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='transformation'/><title type='text'>Transformations Reloaded</title><content type='html'>An object can have one transformation applied to it or it can have many transformations&lt;br /&gt;applied to it. We might only want to translate (move) an object, so we can update the&lt;br /&gt;object’s world matrix to move it around in the world. We might just want the object to&lt;br /&gt;spin around, so we apply a rotation transformation to the object over and over so it will&lt;br /&gt;rotate. We might need an object we created from a 3D editor to be smaller to fit better in&lt;br /&gt;our world. In that case we can apply a scaling transformation to the object. Of course, we&lt;br /&gt;might need to take this object we loaded in from the 3D editor and scale it down and&lt;br /&gt;rotate it 30 degrees to the left so it will face some object and we need to move it closer to&lt;br /&gt;the object it is facing. In this case we would actually do all three types of transformations&lt;br /&gt;to get the desired results. We might even need to rotate it downward 5 degrees as well,&lt;br /&gt;and that is perfectly acceptable.&lt;br /&gt;We can have many different transformations applied to an object. However, there is a&lt;br /&gt;catch—there is always a catch, right? The catch is that because we are doing these transformations&lt;br /&gt;using matrix math we need to be aware of something very important. We are&lt;br /&gt;multiplying our transformation matrices together to get the results we want. Unlike&lt;br /&gt;multiplying normal integers, multiplying matrices is not commutative. This means that&lt;br /&gt;Matrix A * Matrix B != Matrix B * Matrix A. So in our earlier example where we want to&lt;br /&gt;scale our object and rotate it (two different times) and then move it, we will need to be&lt;br /&gt;careful in which order we perform those operations. We will see how to do this a little&lt;br /&gt;later in the chapter.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-3068434066523734256?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/3068434066523734256/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=3068434066523734256' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/3068434066523734256'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/3068434066523734256'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/transformations-reloaded_03.html' title='Transformations Reloaded'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-5930359360937065024</id><published>2008-04-03T21:30:00.000-07:00</published><updated>2008-04-03T21:31:27.897-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='benchmark'/><title type='text'>Creating a Benchmark</title><content type='html'>To get a baseline for our game loop we will start with a new Windows game project. We&lt;br /&gt;can call this project PerformanceBenchmark. We will add a frame rate counter and&lt;br /&gt;update our window title to show just how many frames per second we are getting “out&lt;br /&gt;of the box.”&lt;br /&gt;Now we can set the following properties inside of the constructor:&lt;br /&gt;//Do not synch our Draw method with the Vertical Retrace of our monitor&lt;br /&gt;graphics.SynchronizeWithVerticalRetrace = false;&lt;br /&gt;//Call our Update method at the default rate of 1/60 of a second.&lt;br /&gt;IsFixedTimeStep = true;&lt;br /&gt;The template creates the GraphicsDeviceManager for us. We set the&lt;br /&gt;SynchronizeWithVerticalRetrace property of the manager to false. The default of this&lt;br /&gt;property is true. As the name suggests, this property synchronizes the call to the Draw&lt;br /&gt;method from inside of the XNA Framework’s game loop to coincide with the monitor’s&lt;br /&gt;refresh rate. If the monitor has a refresh rate of 60 Hz, it refreshes every 1/60 seconds or&lt;br /&gt;60 times every second. By default XNA draws to the screen at the same time the monitor&lt;br /&gt;refreshes to keep the scene from appearing jerky. This is typically what we want. However,&lt;br /&gt;Measure, Measure, Measure 37&lt;br /&gt;3&lt;br /&gt;when measuring the change a piece of code has on our frame rate it is difficult to determine&lt;br /&gt;how we are affecting it if we are always drawing 60 fps. We would not know&lt;br /&gt;anything was wrong until we did something that dropped us below that margin keeping&lt;br /&gt;XNA from calling the Draw method fast enough.&lt;br /&gt;We also set the fixed time step property (IsFixedTimeStep) to true. This is the default&lt;br /&gt;value of this property. This property lets XNA know if it should call the Update method&lt;br /&gt;immediately after drawing to the screen (false) or only after a fixed amount of time has&lt;br /&gt;passed (true). This fixed amount of time is 1/60 second and is stored in the property&lt;br /&gt;TargetElapsedTime, which we can change. At this point we do not need the framework&lt;br /&gt;to call Update as often as possible. For this application it does not really matter because&lt;br /&gt;we are not doing anything inside of our Update method.&lt;br /&gt;Let’s add the following private member fields to our Game1.cs file:&lt;br /&gt;private float fps;&lt;br /&gt;private float updateInterval = 1.0f;&lt;br /&gt;private float timeSinceLastUpdate = 0.0f;&lt;br /&gt;private float framecount = 0;&lt;br /&gt;Finally, let’s add the frame rate calculation inside of our Draw method.&lt;br /&gt;float elapsed = (float)gameTime.ElapsedRealTime.TotalSeconds;&lt;br /&gt;framecount++;&lt;br /&gt;timeSinceLastUpdate += elapsed;&lt;br /&gt;if (timeSinceLastUpdate &gt; updateInterval)&lt;br /&gt;{&lt;br /&gt;fps = framecount / timeSinceLastUpdate; //mean fps over updateIntrval&lt;br /&gt;Window.Title = “FPS: “ + fps.ToString() + “ - RT: “ +&lt;br /&gt;gameTime.ElapsedRealTime.TotalSeconds.ToString() + “ - GT: “ +&lt;br /&gt;gameTime.ElapsedGameTime.TotalSeconds.ToString();&lt;br /&gt;framecount = 0;&lt;br /&gt;timeSinceLastUpdate -= updateInterval;&lt;br /&gt;}&lt;br /&gt;The first thing we are doing with the code is storing the elapsed time since the last time&lt;br /&gt;the Draw method was executed. We then increment our frame count along with the variable&lt;br /&gt;that is keeping a running total of the time. We check to see if enough time has passed,&lt;br /&gt;at which point we update our frame rate. We have the updateInterval set at 1 second, but&lt;br /&gt;we can tweak that number if we would like. Once enough time has passed for us to recalculate&lt;br /&gt;our frame rate, we do just that by taking the number of frames and dividing it by&lt;br /&gt;the time it took us to get inside of this condition. We then update the title of the window&lt;br /&gt;with our fps. We also write out the ElapsedRealTime along with the ElapsedGameTime. To&lt;br /&gt;calculate our fps we used the real time. Play with the first two properties we set to see the&lt;br /&gt;effect it has on the time. Remember the SynchronizeWithVerticalRetrace property determines&lt;br /&gt;how often the Draw method gets called and the IsFixedTimeStep property determines&lt;br /&gt;how often the Update method gets called. We can see that the ElapsedRealTime is&lt;br /&gt;associated to the time it took to call our Draw method while the ElapsedGameTime is associated&lt;br /&gt;with the time it took to call our Update method.&lt;br /&gt;CHAPTER 3 38 Performance Considerations&lt;br /&gt;Finally, we reset our frame count along with the timeSinceLastUpdate variable. Let’s run&lt;br /&gt;the application so we can get our baseline for how our machine is performing.&lt;br /&gt;Now that we have our base number we want to make a note of it. This could be done in&lt;br /&gt;an Excel spreadsheet where we can easily track the changes in our performance. We&lt;br /&gt;should always try to run our performance tests under the same conditions. Ideally,&lt;br /&gt;nothing except the game should be run during all of the benchmark testing.&lt;br /&gt;As an example, let’s add the following code inside of the Draw method:&lt;br /&gt;//bad code that shoud not be replicated&lt;br /&gt;Matrix m = Matrix.Identity;&lt;br /&gt;Vector3 v2;&lt;br /&gt;for (int i = 0; i &lt; 1; i++)&lt;br /&gt;{&lt;br /&gt;m = Matrix.CreateRotationX(MathHelper.PiOver4);&lt;br /&gt;m *= Matrix.CreateTranslation(new Vector3(5.0f));&lt;br /&gt;Vector3 v = m.Translation - Vector3.One;&lt;br /&gt;v2 = v + Vector3.One;&lt;br /&gt;}&lt;br /&gt;It does not do anything other than some 3D math that has absolutely no purpose. The&lt;br /&gt;reason we are going through this exercise is to see how our frame rate will drop as we&lt;br /&gt;increment the upper limit of our for loop. The point is that when we start writing real&lt;br /&gt;functionality inside of the Draw method we can measure how our frame rate is handling&lt;br /&gt;the addition of code. On the included CD, this example is called PerformanceTest1.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-5930359360937065024?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/5930359360937065024/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=5930359360937065024' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/5930359360937065024'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/5930359360937065024'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/creating-benchmark_03.html' title='Creating a Benchmark'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-7107385883843078088</id><published>2008-04-03T21:08:00.002-07:00</published><updated>2008-04-03T21:09:24.403-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='create'/><category scheme='http://www.blogger.com/atom/ns#' term='3d'/><category scheme='http://www.blogger.com/atom/ns#' term='3d object'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>Creating 3D Objects</title><content type='html'>In this chapter we examine 3D concepts and how the&lt;br /&gt;XNA Framework exposes different types and objects that&lt;br /&gt;allow us to easily create 3D worlds. We will create a couple&lt;br /&gt;of 3D demos that explain the basics. We will also create 3D&lt;br /&gt;objects directly inside of our code. Finally, we will move&lt;br /&gt;these objects on the screen.&lt;br /&gt;Vertices&lt;br /&gt;Everything in a 3D game is represented by 3D points. There&lt;br /&gt;are a couple of ways to get 3D objects on the screen. We&lt;br /&gt;can plot the points ourselves or we can load them from a&lt;br /&gt;3D file (which has all of the points stored already). Later, in&lt;br /&gt;Chapter 6, “Loading and Texturing 3D Objects,” we will&lt;br /&gt;learn how to load 3D files to use in our games. For now,&lt;br /&gt;we are going to create the points ourselves.&lt;br /&gt;We defined these points with an x, y, and z coordinate (x,&lt;br /&gt;y, z). In XNA we represent a vertex with a vector, which&lt;br /&gt;leads us to the next section.&lt;br /&gt;Vectors&lt;br /&gt;XNA provides three different vector structs for us—&lt;br /&gt;Vector2, Vector3, and Vector4. Vector2 only has an x&lt;br /&gt;and y component. We typically use this 2D vector in 2D&lt;br /&gt;games and when using a texture. Vector3 adds in the z&lt;br /&gt;component. Not only do we store vertices as a vector, but&lt;br /&gt;we also store velocity as a vector. We discuss velocity in&lt;br /&gt;Chapter 19, “Physics Basics.” The last vector struct that&lt;br /&gt;XNA provides for us is a 4D struct appropriately called&lt;br /&gt;Vector4. Later examples in this book will use this struct to&lt;br /&gt;pass color information around as it has four components.&lt;br /&gt;We can perform different math operations on vectors,&lt;br /&gt;which prove to be very helpful. We do not discuss 3D math&lt;br /&gt;in detail in this book as there are many texts out there that&lt;br /&gt;60 CHAPTER 4 Creating 3D Objects&lt;br /&gt;cover it. Fortunately, XNA allows us to use the built-in helper functions without having to&lt;br /&gt;have a deep understanding of the inner workings of the code. With that said, it is&lt;br /&gt;extremely beneficial to understand the math behind the different functions.&lt;br /&gt;Matrices&lt;br /&gt;In XNA a matrix is a 4x 4 table of data. It is a two-dimensional array. An identity matrix,&lt;br /&gt;also referred to as a unit matrix, is similar to the number 1 in that if we multiply any&lt;br /&gt;other number by 1 we always end up with the number we started out with (5 * 1 = 5 ).&lt;br /&gt;Multiplying a matrix by an identity matrix will produce a matrix with the same value as&lt;br /&gt;the original matrix. XNA provides a struct to hold matrix data—not surprisingly, it is&lt;br /&gt;called Matrix.&lt;br /&gt;Transformations&lt;br /&gt;The data a matrix contains are called transformations. There are three common transformations:&lt;br /&gt;translation, scaling, and rotating. These transformations do just that: They transform&lt;br /&gt;our 3D objects.&lt;br /&gt;Translation&lt;br /&gt;Translating an object simply means we are moving an object. We translate an object from&lt;br /&gt;one point to another point by moving each point inside of the object correctly.&lt;br /&gt;Scaling&lt;br /&gt;Scaling an object will make the object larger or smaller. This is done by actually moving&lt;br /&gt;the points in the object closer together or further apart depending on if we are scaling&lt;br /&gt;down or scaling up.&lt;br /&gt;Rotation&lt;br /&gt;Rotating an object will turn the object on one or more axes. By moving the points in 3D&lt;br /&gt;space we can make our object spin.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Transformations Reloaded&lt;br /&gt;&lt;br /&gt;tag: transformation,reloaded,xna&lt;br /&gt;&lt;br /&gt;An object can have one transformation applied to it or it can have many transformations&lt;br /&gt;applied to it. We might only want to translate (move) an object, so we can update the&lt;br /&gt;object’s world matrix to move it around in the world. We might just want the object to&lt;br /&gt;spin around, so we apply a rotation transformation to the object over and over so it will&lt;br /&gt;rotate. We might need an object we created from a 3D editor to be smaller to fit better in&lt;br /&gt;our world. In that case we can apply a scaling transformation to the object. Of course, we&lt;br /&gt;might need to take this object we loaded in from the 3D editor and scale it down and&lt;br /&gt;rotate it 30 degrees to the left so it will face some object and we need to move it closer to&lt;br /&gt;the object it is facing. In this case we would actually do all three types of transformations&lt;br /&gt;to get the desired results. We might even need to rotate it downward 5 degrees as well,&lt;br /&gt;and that is perfectly acceptable.&lt;br /&gt;We can have many different transformations applied to an object. However, there is a&lt;br /&gt;catch—there is always a catch, right? The catch is that because we are doing these transformations&lt;br /&gt;using matrix math we need to be aware of something very important. We are&lt;br /&gt;multiplying our transformation matrices together to get the results we want. Unlike&lt;br /&gt;multiplying normal integers, multiplying matrices is not commutative. This means that&lt;br /&gt;Matrix A * Matrix B != Matrix B * Matrix A. So in our earlier example where we want to&lt;br /&gt;scale our object and rotate it (two different times) and then move it, we will need to be&lt;br /&gt;careful in which order we perform those operations. We will see how to do this a little&lt;br /&gt;later in the chapter.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-7107385883843078088?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/7107385883843078088/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=7107385883843078088' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/7107385883843078088'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/7107385883843078088'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/creating-3d-objects.html' title='Creating 3D Objects'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-609602096883304337</id><published>2008-04-03T21:08:00.001-07:00</published><updated>2008-04-03T21:08:54.175-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='micro benchmark'/><category scheme='http://www.blogger.com/atom/ns#' term='framework'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>Creating a Micro-Benchmark Framework</title><content type='html'>When we are trying to make a particular piece of code run faster because we see that it is&lt;br /&gt;taking more time compared to everything else in our application, we will need to&lt;br /&gt;compare different implementations of completing the same task. This is where microbenchmark&lt;br /&gt;testing can help.&lt;br /&gt;Micro-benchmark testing allows us to take a close look at how fast small bits of code are&lt;br /&gt;performing. There are a couple of items to keep in mind as we use micro-benchmark&lt;br /&gt;testing, though. The first is that we cannot exactly determine best practices from a microbenchmark&lt;br /&gt;test because it is such an isolated case. The second is that although a piece of&lt;br /&gt;code might perform faster in a micro-benchmark test, it might very well take up a lot&lt;br /&gt;more memory and therefore cause the garbage collector to collect its garbage more often.&lt;br /&gt;Optimization Suggestions 43&lt;br /&gt;3&lt;br /&gt;The point here is that although micro-benchmark testing is good and we should do it&lt;br /&gt;(which is why we are going to build a framework for it) we need to be careful of any&lt;br /&gt;assumptions we make solely on what we find out from our micro-benchmark tests.&lt;br /&gt;XNA Game Studio Express not only lets us create game projects, but also allows us to&lt;br /&gt;create library projects. When the library projects are compiled they can be used by other&lt;br /&gt;applications—a game, a Windows form, or even a console application.&lt;br /&gt;We are going to create another application, but this time it is going to be a normal&lt;br /&gt;Windows Game Library project. This class should be called CheckPerformance. We will be&lt;br /&gt;utilizing this library from a console application. The code for the CheckPerformance can&lt;br /&gt;be found in Listing 3.1. The purpose of this class is to create methods that perform the&lt;br /&gt;same tasks different ways. We will then create a console application that calls the different&lt;br /&gt;methods and measure the amount of time it takes to process each method.&lt;br /&gt;LISTING 3.1 The CheckPerformance class has methods that produce the same results&lt;br /&gt;through different means.&lt;br /&gt;public class CheckPerformance&lt;br /&gt;{&lt;br /&gt;private Vector3 cameraReference = new Vector3(0, 0, -1.0f);&lt;br /&gt;private Vector3 cameraPosition = new Vector3(0, 0, 3.0f);&lt;br /&gt;private Vector3 cameraTarget = Vector3.Zero;&lt;br /&gt;private Vector3 vectorUp = Vector3.Up;&lt;br /&gt;private Matrix projection;&lt;br /&gt;private Matrix view;&lt;br /&gt;private float cameraYaw = 0.0f;&lt;br /&gt;public CheckPerformance() { }&lt;br /&gt;public void TransformVectorByValue()&lt;br /&gt;{&lt;br /&gt;Matrix rotationMatrix = Matrix.CreateRotationY(&lt;br /&gt;MathHelper.ToRadians(45.0f));&lt;br /&gt;// Create a vector pointing the direction the camera is facing.&lt;br /&gt;Vector3 transformedReference = Vector3.Transform(cameraReference,&lt;br /&gt;rotationMatrix);&lt;br /&gt;// Calculate the position the camera is looking at.&lt;br /&gt;cameraTarget = cameraPosition + transformedReference;&lt;br /&gt;}&lt;br /&gt;public void TransformVectorByReference()&lt;br /&gt;{&lt;br /&gt;Matrix rotationMatrix = Matrix.CreateRotationY(&lt;br /&gt;MathHelper.ToRadians(45.0f));&lt;br /&gt;// Create a vector pointing the direction the camera is facing.&lt;br /&gt;Vector3 transformedReference;&lt;br /&gt;CHAPTER 3 44 Performance Considerations&lt;br /&gt;Vector3.Transform(ref cameraReference, ref rotationMatrix,&lt;br /&gt;out transformedReference);&lt;br /&gt;// Calculate the position the camera is looking at.&lt;br /&gt;Vector3.Add(ref cameraPosition, ref transformedReference,&lt;br /&gt;out cameraTarget);&lt;br /&gt;}&lt;br /&gt;public void TransformVectorByReferenceAndOut()&lt;br /&gt;{&lt;br /&gt;Matrix rotationMatrix = Matrix.CreateRotationY(&lt;br /&gt;MathHelper.ToRadians(45.0f));&lt;br /&gt;// Create a vector pointing the direction the camera is facing.&lt;br /&gt;Vector3 transformedReference;&lt;br /&gt;Vector3.Transform(ref cameraReference, ref rotationMatrix,&lt;br /&gt;out transformedReference);&lt;br /&gt;// Calculate the position the camera is looking at.&lt;br /&gt;Vector3.Add(ref cameraPosition, ref transformedReference,&lt;br /&gt;out cameraTarget);&lt;br /&gt;}&lt;br /&gt;public void TransformVectorByReferenceAndOutVectorAdd()&lt;br /&gt;{&lt;br /&gt;Matrix rotationMatrix;&lt;br /&gt;Matrix.CreateRotationY(MathHelper.ToRadians(45.0f),&lt;br /&gt;out rotationMatrix);&lt;br /&gt;// Create a vector pointing the direction the camera is facing.&lt;br /&gt;Vector3 transformedReference;&lt;br /&gt;Vector3.Transform(ref cameraReference, ref rotationMatrix,&lt;br /&gt;out transformedReference);&lt;br /&gt;// Calculate the position the camera is looking at.&lt;br /&gt;Vector3.Add(ref cameraPosition, ref transformedReference,&lt;br /&gt;out cameraTarget);&lt;br /&gt;}&lt;br /&gt;public void InitializeTransformWithCalculation()&lt;br /&gt;{&lt;br /&gt;float aspectRatio = (float)640 / (float)480;&lt;br /&gt;projection = Matrix.CreatePerspectiveFieldOfView(&lt;br /&gt;MathHelper.ToRadians(45.0f), aspectRatio, 0.0001f, 1000.0f);&lt;br /&gt;view = Matrix.CreateLookAt(cameraPosition, cameraTarget, Vector3.Up);&lt;br /&gt;}&lt;br /&gt;public void InitializeTransformWithConstant()&lt;br /&gt;{&lt;br /&gt;Optimization Suggestions 45&lt;br /&gt;3&lt;br /&gt;LISTING 3.1 Continued&lt;br /&gt;float aspectRatio = (float)640 / (float)480;&lt;br /&gt;projection = Matrix.CreatePerspectiveFieldOfView(&lt;br /&gt;MathHelper.PiOver4, aspectRatio, 0.0001f, 1000.0f);&lt;br /&gt;view = Matrix.CreateLookAt(cameraPosition, cameraTarget, Vector3.Up);&lt;br /&gt;}&lt;br /&gt;public void InitializeTransformWithDivision()&lt;br /&gt;{&lt;br /&gt;float aspectRatio = (float)640 / (float)480;&lt;br /&gt;projection = Matrix.CreatePerspectiveFieldOfView(&lt;br /&gt;MathHelper.Pi / 4, aspectRatio, 0.0001f, 1000.0f);&lt;br /&gt;view = Matrix.CreateLookAt(cameraPosition, cameraTarget, Vector3.Up);&lt;br /&gt;}&lt;br /&gt;public void InitializeTransformWithConstantReferenceOut()&lt;br /&gt;{&lt;br /&gt;float aspectRatio = (float)640 / (float)480;&lt;br /&gt;Matrix.CreatePerspectiveFieldOfView(&lt;br /&gt;MathHelper.ToRadians(45.0f), aspectRatio, 0.0001f, 1000.0f,&lt;br /&gt;out projection);&lt;br /&gt;Matrix.CreateLookAt(&lt;br /&gt;ref cameraPosition, ref cameraTarget, ref vectorUp, out view);&lt;br /&gt;}&lt;br /&gt;public void InitializeTransformWithPreDeterminedAspectRatio()&lt;br /&gt;{&lt;br /&gt;Matrix.CreatePerspectiveFieldOfView(&lt;br /&gt;MathHelper.ToRadians(45.0f), 1.33333f, 0.0001f, 1000.0f,&lt;br /&gt;out projection);&lt;br /&gt;Matrix.CreateLookAt(&lt;br /&gt;ref cameraPosition, ref cameraTarget, ref vectorUp, out view);&lt;br /&gt;}&lt;br /&gt;public void CreateCameraReferenceWithProperty()&lt;br /&gt;{&lt;br /&gt;Vector3 cameraReference = Vector3.Forward;&lt;br /&gt;Matrix rotationMatrix;&lt;br /&gt;Matrix.CreateRotationY(&lt;br /&gt;MathHelper.ToRadians(45.0f), out rotationMatrix);&lt;br /&gt;// Create a vector pointing the direction the camera is facing.&lt;br /&gt;Vector3 transformedReference;&lt;br /&gt;Vector3.Transform(ref cameraReference, ref rotationMatrix,&lt;br /&gt;out transformedReference);&lt;br /&gt;// Calculate the position the camera is looking at.&lt;br /&gt;CHAPTER 3 46 Performance Considerations&lt;br /&gt;LISTING 3.1 Continued&lt;br /&gt;cameraTarget = cameraPosition + transformedReference;&lt;br /&gt;}&lt;br /&gt;public void CreateCameraReferenceWithValue()&lt;br /&gt;{&lt;br /&gt;Vector3 cameraReference = new Vector3(0, 0, -1.0f);&lt;br /&gt;Matrix rotationMatrix;&lt;br /&gt;Matrix.CreateRotationY(&lt;br /&gt;MathHelper.ToRadians(45.0f), out rotationMatrix);&lt;br /&gt;// Create a vector pointing the direction the camera is facing.&lt;br /&gt;Vector3 transformedReference;&lt;br /&gt;Vector3.Transform(ref cameraReference, ref rotationMatrix,&lt;br /&gt;out transformedReference);&lt;br /&gt;// Calculate the position the camera is looking at.&lt;br /&gt;cameraTarget = cameraPosition + transformedReference;&lt;br /&gt;}&lt;br /&gt;public void RotateWithoutMod()&lt;br /&gt;{&lt;br /&gt;cameraYaw += 2.0f;&lt;br /&gt;if (cameraYaw &gt; 360)&lt;br /&gt;cameraYaw -= 360;&lt;br /&gt;if (cameraYaw &lt; 0)&lt;br /&gt;cameraYaw += 360;&lt;br /&gt;float tmp = cameraYaw;&lt;br /&gt;}&lt;br /&gt;public void RotateWithMod()&lt;br /&gt;{&lt;br /&gt;cameraYaw += 2.0f;&lt;br /&gt;cameraYaw %= 30;&lt;br /&gt;float tmp = cameraYaw;&lt;br /&gt;}&lt;br /&gt;public void RotateElseIf()&lt;br /&gt;{&lt;br /&gt;cameraYaw += 2.0f;&lt;br /&gt;if (cameraYaw &gt; 360)&lt;br /&gt;cameraYaw -= 360;&lt;br /&gt;Optimization Suggestions 47&lt;br /&gt;3&lt;br /&gt;LISTING 3.1 Continued&lt;br /&gt;else if (cameraYaw &lt; 0)&lt;br /&gt;cameraYaw += 360;&lt;br /&gt;float tmp = cameraYaw;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;We do not need to be concerned with the actual contents of the different methods. The&lt;br /&gt;main concept we need to understand at this point is we have different groups of methods&lt;br /&gt;that do the same task but are executed in different ways. We discuss the details of the&lt;br /&gt;Matrix in Chapter 4, “Creating 3D Objects.” For now we can take a look at the last three&lt;br /&gt;methods in the listing and see they are all doing the same thing. All three methods are&lt;br /&gt;adding 2 to a variable cameraYaw and then making sure that the value is between 0 and&lt;br /&gt;360. The idea is that this code would be inside of the game loop reading input from a&lt;br /&gt;device and updating the cameraYaw variable appropriately.&lt;br /&gt;Now we can create the console application that will actually call that class. We need to&lt;br /&gt;add a new Console Application project to the solution and can call this project&lt;br /&gt;XNAPerfStarter. We can name this project XNAPerformanceChecker. The code for&lt;br /&gt;Program.cs is given in Listing 3.2.&lt;br /&gt;LISTING 3.2 The program measures the amount of time it takes to execute the different&lt;br /&gt;CheckPerformance methods.&lt;br /&gt;class Program&lt;br /&gt;{&lt;br /&gt;static int timesToLoop = 10000;&lt;br /&gt;static void Main(string[] args)&lt;br /&gt;{&lt;br /&gt;while (true)&lt;br /&gt;{&lt;br /&gt;XNAPerformanceChecker.CheckPerformance cp =&lt;br /&gt;new XNAPerformanceChecker.CheckPerformance();&lt;br /&gt;Stopwatch sw = new Stopwatch();&lt;br /&gt;//Call all methods once for any JIT-ing that needs to be done&lt;br /&gt;sw.Start();&lt;br /&gt;cp.InitializeTransformWithCalculation();&lt;br /&gt;cp.InitializeTransformWithConstant();&lt;br /&gt;cp.InitializeTransformWithDivision();&lt;br /&gt;cp.InitializeTransformWithConstantReferenceOut();&lt;br /&gt;cp.TransformVectorByReference();&lt;br /&gt;cp.TransformVectorByValue();&lt;br /&gt;CHAPTER 3 48 Performance Considerations&lt;br /&gt;LISTING 3.1 Continued&lt;br /&gt;cp.TransformVectorByReferenceAndOut();&lt;br /&gt;cp.TransformVectorByReferenceAndOutVectorAdd();&lt;br /&gt;cp.CreateCameraReferenceWithProperty();&lt;br /&gt;cp.CreateCameraReferenceWithValue();&lt;br /&gt;sw.Stop();&lt;br /&gt;sw.Reset();&lt;br /&gt;int i;&lt;br /&gt;sw.Start();&lt;br /&gt;for (i = 0; i &lt; timesToLoop; i++)&lt;br /&gt;cp.InitializeTransformWithCalculation();&lt;br /&gt;sw.Stop();&lt;br /&gt;PrintPerformance(“ Calculation”, ref sw);&lt;br /&gt;sw.Reset();&lt;br /&gt;sw.Start();&lt;br /&gt;for (i = 0; i &lt; timesToLoop; i++)&lt;br /&gt;cp.InitializeTransformWithConstant();&lt;br /&gt;sw.Stop();&lt;br /&gt;PrintPerformance(“ Constant”, ref sw);&lt;br /&gt;sw.Reset();&lt;br /&gt;sw.Start();&lt;br /&gt;for (i = 0; i &lt; timesToLoop; i++)&lt;br /&gt;cp.InitializeTransformWithDivision();&lt;br /&gt;sw.Stop();&lt;br /&gt;PrintPerformance(“ Division”, ref sw);&lt;br /&gt;sw.Reset();&lt;br /&gt;sw.Start();&lt;br /&gt;for (i = 0; i &lt; timesToLoop; i++)&lt;br /&gt;cp.InitializeTransformWithConstantReferenceOut();&lt;br /&gt;sw.Stop();&lt;br /&gt;PrintPerformance(“ConstantReferenceOut”, ref sw);&lt;br /&gt;sw.Reset();&lt;br /&gt;sw.Start();&lt;br /&gt;for (i = 0; i &lt; timesToLoop; i++)&lt;br /&gt;cp.InitializeTransformWithPreDeterminedAspectRatio();&lt;br /&gt;sw.Stop();&lt;br /&gt;Optimization Suggestions 49&lt;br /&gt;3&lt;br /&gt;LISTING 3.2 Continued&lt;br /&gt;PrintPerformance(“ AspectRatio”, ref sw);&lt;br /&gt;sw.Reset();&lt;br /&gt;Console.WriteLine();&lt;br /&gt;Console.WriteLine(“——————————————————————-”);&lt;br /&gt;Console.WriteLine();&lt;br /&gt;sw.Start();&lt;br /&gt;for (i = 0; i &lt; timesToLoop; i++)&lt;br /&gt;cp.TransformVectorByReference();&lt;br /&gt;sw.Stop();&lt;br /&gt;PrintPerformance(“ Reference”, ref sw);&lt;br /&gt;sw.Reset();&lt;br /&gt;sw.Start();&lt;br /&gt;for (i = 0; i &lt; timesToLoop; i++)&lt;br /&gt;cp.TransformVectorByValue();&lt;br /&gt;sw.Stop();&lt;br /&gt;PrintPerformance(“ Value”, ref sw);&lt;br /&gt;sw.Reset();&lt;br /&gt;sw.Start();&lt;br /&gt;for (i = 0; i &lt; timesToLoop; i++)&lt;br /&gt;cp.TransformVectorByReferenceAndOut();&lt;br /&gt;sw.Stop();&lt;br /&gt;PrintPerformance(“ReferenceAndOut”, ref sw);&lt;br /&gt;sw.Reset();&lt;br /&gt;sw.Start();&lt;br /&gt;for (i = 0; i &lt; timesToLoop; i++)&lt;br /&gt;cp.TransformVectorByReferenceAndOutVectorAdd();&lt;br /&gt;sw.Stop();&lt;br /&gt;PrintPerformance(“RefOutVectorAdd”, ref sw);&lt;br /&gt;sw.Reset();&lt;br /&gt;Console.WriteLine();&lt;br /&gt;Console.WriteLine(“——————————————————————-”);&lt;br /&gt;Console.WriteLine();&lt;br /&gt;sw.Start();&lt;br /&gt;CHAPTER 3 50 Performance Considerations&lt;br /&gt;LISTING 3.2 Continued&lt;br /&gt;for (i = 0; i &lt; timesToLoop; i++)&lt;br /&gt;cp.CreateCameraReferenceWithProperty();&lt;br /&gt;sw.Stop();&lt;br /&gt;PrintPerformance(“Property”, ref sw);&lt;br /&gt;sw.Reset();&lt;br /&gt;sw.Start();&lt;br /&gt;for (i = 0; i &lt; timesToLoop; i++)&lt;br /&gt;cp.CreateCameraReferenceWithValue();&lt;br /&gt;sw.Stop();&lt;br /&gt;PrintPerformance(“ Value”, ref sw);&lt;br /&gt;sw.Reset();&lt;br /&gt;Console.WriteLine();&lt;br /&gt;Console.WriteLine(“——————————————————————-”);&lt;br /&gt;Console.WriteLine();&lt;br /&gt;sw.Start();&lt;br /&gt;for (i = 0; i &lt; timesToLoop; i++)&lt;br /&gt;cp.RotateWithMod();&lt;br /&gt;sw.Stop();&lt;br /&gt;PrintPerformance(“ RotateWithMod”, ref sw);&lt;br /&gt;sw.Reset();&lt;br /&gt;sw.Start();&lt;br /&gt;for (i = 0; i &lt; timesToLoop; i++)&lt;br /&gt;cp.RotateWithoutMod();&lt;br /&gt;sw.Stop();&lt;br /&gt;PrintPerformance(“RotateWithoutMod”, ref sw);&lt;br /&gt;sw.Reset();&lt;br /&gt;sw.Start();&lt;br /&gt;for (i = 0; i &lt; timesToLoop; i++)&lt;br /&gt;cp.RotateElseIf();&lt;br /&gt;sw.Stop();&lt;br /&gt;PrintPerformance(“ RotateElseIf”, ref sw);&lt;br /&gt;sw.Reset();&lt;br /&gt;string command = Console.ReadLine();&lt;br /&gt;Optimization Suggestions 51&lt;br /&gt;3&lt;br /&gt;LISTING 3.2 Continued&lt;br /&gt;if (command.ToUpper().StartsWith(“E”) ||&lt;br /&gt;command.ToUpper().StartsWith(“Q”))&lt;br /&gt;break;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;static void PrintPerformance(string label, ref Stopwatch sw)&lt;br /&gt;{&lt;br /&gt;Console.WriteLine(label + “ – Avg: “ +&lt;br /&gt;((float)((float)(sw.Elapsed.Ticks * 100) /&lt;br /&gt;(float)timesToLoop)).ToString(“F”) +&lt;br /&gt;“ Total: “ + sw.Elapsed.TotalMilliseconds.ToString());&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;We need to also add the following using clause to the top of our Program.cs file:&lt;br /&gt;using System.Diagnostics;&lt;br /&gt;The System.Diagnostics class gives us access to the Stopwatch we are using to keep track&lt;br /&gt;of the time it takes to process the different methods. After starting the timer we then loop&lt;br /&gt;100,000 times and call a method in the CheckPerformance class we created earlier. Once&lt;br /&gt;the loop finishes executing the method the specified number of times, we stop the stopwatch&lt;br /&gt;and print out our results to the console. When using the Stopwatch object we need&lt;br /&gt;to make sure that if we want to start another test that we first call the Reset method. This&lt;br /&gt;isn’t built into the Stop method in case we just want to pause the timer and start it back&lt;br /&gt;up for some reason. We could also use the static StartNew method instead of the instance&lt;br /&gt;Start method. The StartNew method effectively resets the timer as it returns a new&lt;br /&gt;instance of the Stopwatch.&lt;br /&gt;When we are trying to measure performance on pieces of code that perform very fast&lt;br /&gt;(even inside of a large loop) it is important to be able to track exactly how much time it&lt;br /&gt;took, even down to the nanosecond level.&lt;br /&gt;Typically timing things in seconds does not give us the granularity we need to see how&lt;br /&gt;long something is really taking, so the next unit of time we can measure against is&lt;br /&gt;milliseconds. There are 1,000 milliseconds in a second. Next comes the microsecond, and&lt;br /&gt;there are 1,000 microseconds in a millisecond. Next is the tick, which is what the&lt;br /&gt;TimeSpan object uses. There are 10 ticks in a microsecond. Finally, we come to the&lt;br /&gt;nanosecond. There are 100 nanoseconds in each tick. A nanosecond is 1/1,000,000,000&lt;br /&gt;(one billionth) of a second. Table 3.1 shows the relationships between the different&lt;br /&gt;measurements of time.&lt;br /&gt;CHAPTER 3 52 Performance Considerations&lt;br /&gt;LISTING 3.2 Continued&lt;br /&gt;TABLE 3.1 Time Measurement Relationships&lt;br /&gt;Nanoseconds Ticks Microseconds Milliseconds Seconds&lt;br /&gt;100 1 0.1 0.0001 0.0000001&lt;br /&gt;10,000 100 10.0 0.0100 0.0000100&lt;br /&gt;100,000 1,000 100.0 0.1000 0.0001000&lt;br /&gt;1,000,000 10,000 1,000.0 1.0000 0.0010000&lt;br /&gt;10,000,000 100,000 10,000.0 10.0000 0.0100000&lt;br /&gt;100,000,000 1,000,000 100,000.0 100.0000 0.1000000&lt;br /&gt;1,000,000,000 10,000,000 1,000,000.0 1,000.0000 1.0000000&lt;br /&gt;PrintPerformance, our method to print out the performance measurements, takes in the&lt;br /&gt;label that describes what we are measuring along with a reference to Stopwatch object.&lt;br /&gt;TimeSpan is the type the .NET Framework uses to measure time. The smallest unit of time&lt;br /&gt;measurement this type allows is a tick.&lt;br /&gt;Because we want to measure our time in nanoseconds, we multiply the number of elapsed&lt;br /&gt;ticks by 100. Then we take the total number of nanoseconds and divide by the number of&lt;br /&gt;times we executed the method. Finally, we display the average number of nanoseconds&lt;br /&gt;along with total number of milliseconds the task took to execute.&lt;br /&gt;When we print out our measurements we want the average time it took to execute a&lt;br /&gt;method for the number of iterations we told it to loop. The reason we do this instead of&lt;br /&gt;just running it once is so that we can easily determine a more accurate number. In fact,&lt;br /&gt;we even run an outer loop (that we exit out of by entering text that starts with “E” or&lt;br /&gt;“Q”) to account for anomalies in performance on the machine in general.&lt;br /&gt;An additional item to note about this code is that we call each method of the&lt;br /&gt;CheckPerformance object once before we start measuring execution times. The reason we&lt;br /&gt;do this is so the compiler can do any just-in-time compiling for the methods we will be&lt;br /&gt;calling so we are not taking that time into account.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-609602096883304337?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/609602096883304337/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=609602096883304337' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/609602096883304337'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/609602096883304337'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/creating-micro-benchmark-framework.html' title='Creating a Micro-Benchmark Framework'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-8668115243815413409</id><published>2008-04-03T21:07:00.002-07:00</published><updated>2008-04-03T21:08:15.589-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='understand'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='garbage'/><category scheme='http://www.blogger.com/atom/ns#' term='collector'/><title type='text'>Understanding the Garbage Collector</title><content type='html'>A big plus of writing managed code is the fact that we do not need to worry about&lt;br /&gt;memory leaks from the sense of losing pointers to referenced memory. We still have&lt;br /&gt;“memory leaks” in managed code, but whenever the term is used it is referring to not&lt;br /&gt;decommissioning variables in a timely fashion. We would have a memory leak if we kept&lt;br /&gt;a handle on a pointer that we should have set to null. It would remain in memory until&lt;br /&gt;the game exits.&lt;br /&gt;We should use the using statement. An example of the using statement can be found in&lt;br /&gt;the program.cs file that is generated for us by the game template. The entry point of the&lt;br /&gt;program uses this using statement to create our game object and then to call its Run&lt;br /&gt;method. The using statement effectively puts a try/finally block around the code while&lt;br /&gt;putting a call to the object’s Dispose method inside of the finally block.&lt;br /&gt;Garbage collection concerns on Windows are not as large as those on the Xbox 360.&lt;br /&gt;However, if we optimize our code to run well on the Xbox 360 in regard to garbage&lt;br /&gt;collection, the game will also perform well on Windows.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-8668115243815413409?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/8668115243815413409/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=8668115243815413409' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/8668115243815413409'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/8668115243815413409'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/understanding-garbage-collector.html' title='Understanding the Garbage Collector'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-7341566990603006697</id><published>2008-04-03T21:07:00.001-07:00</published><updated>2008-04-03T21:07:47.999-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='manage'/><category scheme='http://www.blogger.com/atom/ns#' term='managing'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='memory'/><title type='text'>Managing Memory</title><content type='html'>There are two types of objects in the .NET Framework: reference and value. Examples of&lt;br /&gt;value types are enums, integral types (byte, short, int, long), floating types (single, double,&lt;br /&gt;float), primitive types (bool, char), and structs. Examples of objects that are reference&lt;br /&gt;types are arrays, exceptions, attributes, delegates, and classes. Value types have their data&lt;br /&gt;stored on the current thread’s stack and the managed heap is where reference types find&lt;br /&gt;themselves.&lt;br /&gt;By default, when we pass variables into methods we pass them by value. This means for&lt;br /&gt;value types we are actually passing a copy of the data on the stack, so anything we do to&lt;br /&gt;that variable inside of the method does not affect the original memory. When we pass in&lt;br /&gt;a reference type we are actually passing a copy of the reference to the data. The actual&lt;br /&gt;data is not copied, just the address of the memory. Because of this, we should pass large&lt;br /&gt;CHAPTER 3 40 Performance Considerations&lt;br /&gt;value types by reference instead of by value when appropriate. It is much faster to copy&lt;br /&gt;an address of a large value type than its actual data.&lt;br /&gt;We use the ref keyword to pass the objects as reference to our methods. We should not&lt;br /&gt;use this keyword on reference types as it will actually slow things down. We should use&lt;br /&gt;the keyword on value types (like structs) that have a large amount of data it would need&lt;br /&gt;to copy if passed by value.&lt;br /&gt;The other thing to note is that even if we have a reference type and we pass it into a&lt;br /&gt;method that takes an object type and we box (implicitly or explicitly), then a copy of the&lt;br /&gt;data is actually created as well—not just the address to the original memory. For example,&lt;br /&gt;consider a class that takes a general object type (like an ArrayList’s Add method). We pass&lt;br /&gt;in a reference type, but instead of just the reference being passed across, a copy of the&lt;br /&gt;data is created and then a reference to that copy of the data is passed across. This eats up&lt;br /&gt;memory and causes the garbage collector to run more often. To avoid this we need to use&lt;br /&gt;generics whenever possible.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-7341566990603006697?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/7341566990603006697/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=7341566990603006697' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/7341566990603006697'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/7341566990603006697'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/managing-memory.html' title='Managing Memory'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-7363799203713275689</id><published>2008-04-03T21:05:00.000-07:00</published><updated>2008-04-03T21:06:34.297-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='install'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='c'/><title type='text'>Installing Visual C# Express</title><content type='html'>To get started, we must have the software installed. Let’s start by installing Visual C#&lt;br /&gt;Express. Visual C# Express is the IDE that is required to run XNA Game Studio Express.&lt;br /&gt;XNA requires C# due to how the Content Pipeline is used. There are some people who&lt;br /&gt;have successfully created demos using other languages such as VB.NET and even F#.&lt;br /&gt;However, this is not supported by Microsoft currently and won’t be discussed in this&lt;br /&gt;book. This book assumes you have a good understanding of C#. If you know C++, Java, or&lt;br /&gt;VB.NET, you should be able to pick up C# pretty quickly.&lt;br /&gt;I am going to be detailed in the steps to make sure that anyone who has not worked with&lt;br /&gt;Visual C# Express will be able to get it installed with no issues. Feel free to skip this&lt;br /&gt;section if you already have Visual C# Express installed.&lt;br /&gt;To install Visual C# Express, follow these steps:&lt;br /&gt;1. You will need to be connected to the Internet to install the application. The application&lt;br /&gt;can be downloaded by browsing to&lt;br /&gt;http://msdn.microsoft.com/vstudio/express/downloads/ and clicking the Visual C#&lt;br /&gt;Express Go button to download the vcssetup.exe setup program.&lt;br /&gt;2. Optional. On the Welcome to Setup screen select the check box to send data about&lt;br /&gt;your setup experience to Microsoft. This way if something goes awry, Microsoft can&lt;br /&gt;get the data and try to make the experience better the next time around. This&lt;br /&gt;screen is shown in Figure 1.1.&lt;br /&gt;11&lt;br /&gt;1&lt;br /&gt;Installing Visual C# Express&lt;br /&gt;FIGURE 1.1 Select the check box if you want the system to provide feedback to Microsoft&lt;br /&gt;about your installation experience.&lt;br /&gt;3. Click Next to continue.&lt;br /&gt;4. The next screen is the End-User License Agreement. If you accept the terms, select&lt;br /&gt;the check box and click Next.&lt;br /&gt;5. The following screen, shown in Figure 1.2, has two installation options you can&lt;br /&gt;check. Neither of these options is required to utilize XNA.&lt;br /&gt;FIGURE 1.2 Neither of these options is required to utilize XNA.&lt;br /&gt;CHAPTER 1 Introducing the XNA Framewor12 k&lt;br /&gt;6. Click Next to continue.&lt;br /&gt;7. The next screen, shown in Figure 1.3, asks where we would like to install Visual C#&lt;br /&gt;Express. It is going to install other required applications including Microsoft .NET&lt;br /&gt;Framework 2.0. This is required, as C# runs on the .NET Framework. You will also&lt;br /&gt;notice it requires more than 300MB of space.&lt;br /&gt;8. Click Next to continue.&lt;br /&gt;FIGURE 1.3 Specify which directory you want Visual C# Express to be installed in.&lt;br /&gt;9. Now we are looking at the Installation Progress screen where we will be able to&lt;br /&gt;monitor the progress of the installation.&lt;br /&gt;10. Finally, on the Setup Complete screen we can see the Windows Update link we can&lt;br /&gt;click on to get any of the latest service packs for Visual C# Express.&lt;br /&gt;11. Click Exit to complete the installation.&lt;br /&gt;We have successfully installed the first piece of the pie to start creating excellent games&lt;br /&gt;with XNA! Before we continue to the next piece of software, we need to open up Visual&lt;br /&gt;C# Express. It might take a couple of minutes to launch the first time the application is&lt;br /&gt;loaded. Once the Visual C# Express is loaded we should see the Start Page as shown in&lt;br /&gt;Figure 1.4.&lt;br /&gt;Installing Visual C# Express 13&lt;br /&gt;1&lt;br /&gt;FIGURE 1.4 This is the Start Page inside of Visual C# Express.&lt;br /&gt;The following procedure is optional, but it does ensure that everything is working&lt;br /&gt;correctly on our machine.&lt;br /&gt;1. In the Recent Projects section, find Create Project and click the link. You can also&lt;br /&gt;create a new project under the File menu.&lt;br /&gt;2. Visual C# Express installed several default templates that we can choose from. Select&lt;br /&gt;the Windows Application template as displayed in Figure 1.5.&lt;br /&gt;3. You can leave the name set to WindowsApplication1 as we will just be discarding&lt;br /&gt;this project when we are done.&lt;br /&gt;FIGURE 1.5 The New Project dialog box allows you to choose from the default templates to&lt;br /&gt;create an application.&lt;br /&gt;CHAPTER 1 Introducing the XNA Framewor14 k&lt;br /&gt;4. Click OK to create the application.&lt;br /&gt;At this point a new project should have been created and we should be looking at a blank&lt;br /&gt;Windows Form called Form1.&lt;br /&gt;5. Press Ctrl+F5 or click Start Without Debugging on the Debug menu.&lt;br /&gt;If everything compiled correctly, the form we just saw in design mode should actually&lt;br /&gt;be running. Granted, it doesn’t do anything, but it does prove that we can compile and&lt;br /&gt;run C# through Visual C# Express. The end result can be seen in Figure 1.6. Let’s close&lt;br /&gt;down the application we just created as well as Visual C# Express. Feel free to discard&lt;br /&gt;the application.&lt;br /&gt;FIGURE 1.6 This is a C# Windows Form application after compiling and running the default&lt;br /&gt;template.&lt;br /&gt;Installing the DirectX Runtime&lt;br /&gt;We also need the DirectX 9 runtime if it isn’t already on the machine. To get started,&lt;br /&gt;follow these steps:&lt;br /&gt;1. Run the dxwebsetup.exe file from Microsoft’s website. This can be found by clicking&lt;br /&gt;on the DirectX Runtime Web Installer link at the bottom of the Creator’s Club&lt;br /&gt;Resources—Essentials web page http://creators.xna.com/Resources/Essentials.aspx.&lt;br /&gt;This file contains the redistribution package of the February 2007 DirectX 9.&lt;br /&gt;You will need to be connected to the Internet so it can completely install the&lt;br /&gt;application.&lt;br /&gt;2. We are greeted with the End-User License Agreement. Handle with care.&lt;br /&gt;3. The next screen is a dialog box asking where we would like the installation files to&lt;br /&gt;be stored. We can pick any directory we want as long as we remember it so we can&lt;br /&gt;actually install the runtime—we are simply extracting the files needed to install the&lt;br /&gt;runtime.&lt;br /&gt;4. Click OK to continue.&lt;br /&gt;5. We will be prompted to create that directory if the directory entered doesn’t exist.&lt;br /&gt;Click Yes to continue.&lt;br /&gt;6. Wait for the dialog box with the progress bar to finish unpacking the files.&lt;br /&gt;Now we can actually install the runtime by following these steps:&lt;br /&gt;1. Browse to the folder where we installed the files and run the dxsetup.exe file to&lt;br /&gt;actually install DirectX 9 onto the machine.&lt;br /&gt;2. The welcome screen we see includes the End-User License Agreement. Select the&lt;br /&gt;appropriate radio button to continue.&lt;br /&gt;3. Following the agreement is a screen stating that it will install DirectX—click Next.&lt;br /&gt;4. Once it finishes installing (a progress bar will be visible while it is installing the&lt;br /&gt;files) we will be presented with the Installation Complete screen.&lt;br /&gt;5. Simply click Finish to exit the setup.&lt;br /&gt;Now, we can move on to installing XNA Game Studio Express.&lt;br /&gt;Installing XNA Game Studio Express&lt;br /&gt;To use XNA Game Studio Express we must use Visual C# Express. We cannot use Visual&lt;br /&gt;Studio .NET Professional nor can we use any other IDE. Although there are people who&lt;br /&gt;have successfully been able to run XNA and even get the Content Pipeline (which we talk&lt;br /&gt;about in Part III of the book) to work in Visual Studio .NET Professional, it is not officially&lt;br /&gt;supported by Microsoft and is not covered in this book.&lt;br /&gt;WARNING&lt;br /&gt;You must run the Visual C# Express IDE at least one time before installing XNA Game&lt;br /&gt;Studio Express. If this is not done, not all of the functionality will be installed. If XNA&lt;br /&gt;Game Studio Express was installed prematurely, you will need to uninstall XNA Game&lt;br /&gt;Studio Express and run Visual C# Express and then exit the IDE. Then you will be able&lt;br /&gt;to reinstall XNA Game Studio Express.&lt;br /&gt;To get started complete the following steps:&lt;br /&gt;1. Run the xnagse_setup.msi file from Microsoft’s website. The file can be downloaded&lt;br /&gt;by clicking on the top link of the Creator’s Club Resources—Essentials web site&lt;br /&gt;http://creators.xna.com/Resources/Essentials.aspx.&lt;br /&gt;2. Click Next to get past the setup welcome screen.&lt;br /&gt;3. The next screen is the End-User License Agreement. If you accept the terms, select&lt;br /&gt;the check box and click Next.&lt;br /&gt;4. This will open up a notification dialog box that explains that the Windows Firewall&lt;br /&gt;will have a rule added to it to allow communication between the computer and the&lt;br /&gt;Xbox 360. This can be seen in Figure 1.7.&lt;br /&gt;Installing XNA Game Studio Express 15&lt;br /&gt;1&lt;br /&gt;FIGURE 1.7 XNA Game Studio Express modifies the Windows Firewall so an Xbox 360 and&lt;br /&gt;the PC can talk to each other.&lt;br /&gt;5. Click Install to continue. The next screen shows the progress of the installation.&lt;br /&gt;6. Once it has completed installing all of the required files we will be presented with&lt;br /&gt;the completion dialog box. Simply click Finish to exit the setup.&lt;br /&gt;After we have installed XNA Game Studio Express, we can go to the Start menu and see it&lt;br /&gt;added a few more items than those contained in the IDE. Make sure to take time and read&lt;br /&gt;through some of the XNA Game Studio Express documentation. There is also a Tools&lt;br /&gt;folder that contains a couple of tools we will be looking at later. We will be discussing the&lt;br /&gt;XACT tool in Chapter 6, “Loading and Texturing 3D Objects,” and the XNA Framework&lt;br /&gt;Remote Performance Monitor for Xbox 360 application in Chapter 3, “Performance&lt;br /&gt;Considerations.” Go ahead and open the IDE by clicking XNA Game Studio Express on&lt;br /&gt;the Start menu.&lt;br /&gt;Hmm, this looks identical to the Visual C# Express IDE. There is a good reason for this—it&lt;br /&gt;is the same application! When we installed XNA Game Studio Express it added properties&lt;br /&gt;to Visual C# Express to allow it to behave differently under certain circumstances. Mainly&lt;br /&gt;it added some templates, which we will look at shortly, and it added the ability for Visual&lt;br /&gt;C# Express to handle content via the XNA Content Pipeline. It also added a way for us to&lt;br /&gt;send data to our Xbox 360, as we will see in the next chapter.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-7363799203713275689?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/7363799203713275689/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=7363799203713275689' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/7363799203713275689'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/7363799203713275689'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/installing-visual-c-express.html' title='Installing Visual C# Express'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-148551349707119893.post-8140339328583737861</id><published>2008-04-03T21:04:00.002-07:00</published><updated>2008-04-03T21:05:55.823-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='introduce'/><category scheme='http://www.blogger.com/atom/ns#' term='xna game'/><category scheme='http://www.blogger.com/atom/ns#' term='xna framework'/><category scheme='http://www.blogger.com/atom/ns#' term='express'/><title type='text'>Introducing the XNA Framework and XNA Game Studio Express</title><content type='html'>Most developers I know decided to enter the computer&lt;br /&gt;field and specifically programming because of computer&lt;br /&gt;games. Game development can be one of the most challenging&lt;br /&gt;disciplines of software engineering—it can also be&lt;br /&gt;the most rewarding!&lt;br /&gt;Never before has it been possible for the masses to create&lt;br /&gt;games for a game console, much less a next generation&lt;br /&gt;game console. We are coming in on the ground floor of a&lt;br /&gt;technology that is going to experience tremendous growth.&lt;br /&gt;Microsoft is leading the way into how content will be&lt;br /&gt;created for game consoles. Soon other game console manufacturers&lt;br /&gt;will be jumping at a way to allow the public to&lt;br /&gt;create content for their machines. The great news for the&lt;br /&gt;Xbox 360 is that Microsoft has spent so much time over&lt;br /&gt;the years creating productive and stable development environments&lt;br /&gt;for programmers. We will be installing one of&lt;br /&gt;Microsoft’s latest integrated development environments&lt;br /&gt;(IDEs) in this chapter. Before we get to that, let’s take a look&lt;br /&gt;at the technology we discuss in this site—XNA.&lt;br /&gt;&lt;br /&gt;What Is the XNA Framework?&lt;br /&gt;You have probably heard the statement, “To know where&lt;br /&gt;you are going, you need to know where you have been.”&lt;br /&gt;I am uncertain if that is entirely true, but I do believe it&lt;br /&gt;applies here. Before we dig into exactly what XNA is and&lt;br /&gt;what it can do for us, let’s take a moment to look at&lt;br /&gt;DirectX because that is what the XNA Framework is&lt;br /&gt;built on.&lt;br /&gt;&lt;br /&gt;The Foundation of the XNA Framework&lt;br /&gt;Let’s take a journey back to the days of DOS on the PC. When programming games,&lt;br /&gt;graphic demos, and the like in DOS, programmers typically had to write low-level code to&lt;br /&gt;talk directly to the sound card, graphics cards, and input devices. This was tedious and&lt;br /&gt;the resulting code was error prone because different manufacturers would handle different&lt;br /&gt;BIOS interrupts, IO ports, and memory banks—well, differently, so the code would work&lt;br /&gt;on one system and not another.&lt;br /&gt;Later, Microsoft released the Windows 95 operating system. Many game programmers&lt;br /&gt;were skeptical at writing games for Windows—and rightly so—because there was no way&lt;br /&gt;to get down to hardware level to do things that required a lot of speed. Windows 95 had&lt;br /&gt;a protected memory model that kept developers from directly accessing the low-level&lt;br /&gt;interrupts of the hardware.&lt;br /&gt;To solve this problem, Microsoft created a technology called DirectX. It was actually&lt;br /&gt;called Windows Game SDK to begin with, but quickly switched names after a reporter&lt;br /&gt;poked fun at the API names DirectDraw, DirectSound, and DirectPlay, calling the SDK&lt;br /&gt;Direct “X.” Microsoft ran with the name and DirectX 1.0 was born a few months after&lt;br /&gt;Windows 95 was released. I remember working with DirectDraw for a couple of demos&lt;br /&gt;back when this technology first came out.&lt;br /&gt;Because of DirectX, developers had a way to write games with one source that would work&lt;br /&gt;on all PCs regardless of their hardware. Hardware vendors were eager to work with&lt;br /&gt;Microsoft on standardizing an interface to access their hardware. They created device&lt;br /&gt;drivers to which DirectX would map its API, so all of the work that previously had to be&lt;br /&gt;done by game programmers was taken care of, and programmers could then spend their&lt;br /&gt;time doing what they wanted to—write games! Vendors called this a Hardware&lt;br /&gt;Abstraction Layer (HAL). They also developed a Hardware Emulation Layer (HEL), which&lt;br /&gt;emulates hardware through software in case hardware isn’t present. Of course, this is&lt;br /&gt;slower but it allowed certain games to be run on machines with no special hardware.&lt;br /&gt;After a couple of years Microsoft released DirectX 3.0, which ran on Windows NT 4 as&lt;br /&gt;well as Windows 95. As part of those upgrades, they introduced Direct3D. This allowed&lt;br /&gt;developers to create 3D objects inside of 3D worlds. DirectX 4 was never released, but&lt;br /&gt;DirectX 5 was released in 1997 and later had some upgrades to work under Windows 98.&lt;br /&gt;When DirectX 8 came on the scene in 2000, some of the newly available graphics hardware&lt;br /&gt;had vertex and pixel shaders. As a result, Microsoft added in a way to pass custom&lt;br /&gt;program code to the hardware. Through assembly code, the game developer could manipulate&lt;br /&gt;the data the main game passed to the graphics card. This assembly code was&lt;br /&gt;consumed directly by the graphics hardware.&lt;br /&gt;When there was no graphics hardware, games were slow, but they were very flexible.&lt;br /&gt;Later, as hardware rendering became prominent, the games were faster, but they were not&lt;br /&gt;very flexible in that all of the games really started to look the same. Now with shaders,&lt;br /&gt;the speed of the hardware is combined with the flexibility for each game to render and&lt;br /&gt;light its 3D content differently.&lt;br /&gt;&lt;br /&gt;This brings us to present-day DirectX: We are up to DirectX 9 and 10. Before I talk about&lt;br /&gt;DirectX 9, I spend some time talking about DirectX 10. DirectX 10 was released at the&lt;br /&gt;same time as Microsoft Windows Vista. In fact, DirectX 10 only works on Vista. This is&lt;br /&gt;largely due to the fact that Microsoft has made major changes in the driver model for this&lt;br /&gt;operating system. DirectX 10 also requires Shader Model 4.0 hardware.&lt;br /&gt;The Xbox 360 runs on DirectX 9 plus some additional partial support for Shader Model&lt;br /&gt;3.0 functionality. DirectX 9 is the foundation for Managed DirectX, an API that exposed&lt;br /&gt;the core DirectX functionality to .NET Framework developers. There was a lot of concern&lt;br /&gt;about whether this “wrapper” could be as fast as the C++ counterparts. Fortunately, it was&lt;br /&gt;almost as fast—about 98 percent was the benchmark touted. I experienced these benchmark&lt;br /&gt;speeds firsthand while on the beta team for this technology. I fell in love with&lt;br /&gt;Managed DirectX.&lt;br /&gt;The XNA Framework used the lessons learned from Managed DirectX and used that foundation&lt;br /&gt;as a launching pad. To be clear, XNA was built from the ground up and was not&lt;br /&gt;built on top of Managed DirectX. It didn’t use the same namespaces as Managed DirectX&lt;br /&gt;and is not simply pointing to the Managed DirectX methods in the background.&lt;br /&gt;Although XNA utilizes DirectX 9 in the background, there are no references to DirectX’s&lt;br /&gt;API like there were in Managed DirectX.&lt;br /&gt;XNA Today&lt;br /&gt;XNA is actually a generic term much like the term .NET. XNA really refers to anything&lt;br /&gt;that Microsoft produces that relates to game developers. The XNA Framework is the API&lt;br /&gt;we are discussing. The final piece to XNA is the XNA Game Studio Express application,&lt;br /&gt;which we discuss in detail later. This is the IDE we use to develop our XNA games.&lt;br /&gt;TIP&lt;br /&gt;In this book, whenever we use the term XNA, we are really referring to the XNA&lt;br /&gt;Framework unless otherwise noted.&lt;br /&gt;XNA allows us to do a lot of things. We have easy access to the input devices (keyboard,&lt;br /&gt;game pad or controller, mouse). XNA gives us easy access to the graphics hardware. We&lt;br /&gt;are able to easily control audio through XNA. XNA provides the ability for us to store&lt;br /&gt;information like high scores and even saved games. XNA does not currently have any&lt;br /&gt;networking capability. Microsoft wants to use the Xbox Live technology for adding&lt;br /&gt;network support to XNA. However, there is more work to be done to make sure Microsoft&lt;br /&gt;can provide multiplayer functionality in a secure manner.&lt;br /&gt;To get started using XNA we have to install some software. We need to install the latest&lt;br /&gt;version of DirectX 9 as well as have a graphics card that supports DirectX 9.0c and Shader&lt;br /&gt;Model 1.1. (You should get a card that supports Shader Model 2.0 as some of the examples,&lt;br /&gt;including the starter kit we use in this chapter and the next one, will not run&lt;br /&gt;without it.) We also need to install Visual C# Express, the DirectX 9 runtime, and finally&lt;br /&gt;XNA Game Studio Express. Fortunately, all of the software is free! If you don’t have&lt;br /&gt;10 CHAPTER 1 Introducing the XNA Framework and XNA Game Studio Express&lt;br /&gt;graphics hardware that can support Shader Model 2.0 you can pick up a card relatively&lt;br /&gt;inexpensively for about $35 USD. If possible, you should purchase a graphics card that&lt;br /&gt;can support Shader Model 3.0, as a couple of examples at the end of the book require it.&lt;br /&gt;At this point, games cannot be created for commercial use on the Xbox 360 but Microsoft&lt;br /&gt;has mentioned they are interested in supporting commercial games in future versions.&lt;br /&gt;Fortunately, we can create community games for the Xbox 360 with the Express versions.&lt;br /&gt;XNA Game Studio Express is great for the game hobbyist, a student, or someone just&lt;br /&gt;getting started because you do not have to shell out a lot of (any!) money to get up and&lt;br /&gt;running. One exception to this is if you actually want to deploy your games on your&lt;br /&gt;Xbox 360. To do that, you will need to subscribe to the XNA Creators Club for $99 USD a&lt;br /&gt;year (or $49 USD for four months). Remember, writing games for the PC using XNA is&lt;br /&gt;totally free!&lt;br /&gt;Oh, in case you are wondering what XNA stands for, XNA’s Not Acronymed (or so&lt;br /&gt;Microsoft says in the XNA FAQ).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/148551349707119893-8140339328583737861?l=xnahelp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xnahelp.blogspot.com/feeds/8140339328583737861/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=148551349707119893&amp;postID=8140339328583737861' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/8140339328583737861'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/148551349707119893/posts/default/8140339328583737861'/><link rel='alternate' type='text/html' href='http://xnahelp.blogspot.com/2008/04/introducing-xna-framework-and-xna-game.html' title='Introducing the XNA Framework and XNA Game Studio Express'/><author><name>Golden Beast</name><uri>http://www.blogger.com/profile/13070188711291410632</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_kCEjrKZLCfg/R_PLKy5suII/AAAAAAAAAAM/DYjFC0CC0q8/S220/ajstylesttnnaa.jpg'/></author><thr:total>0</thr:total></entry></feed>
