|
Controllo della rotazione del modello 3D con il joypad In questo capitolo vediamo come sia possibile scrivere un set di istruzioni al fine di controllare l'oggetto in movimento con una periferica di controllo. Per come è stato studiato il framework di XNA, è possibile utilizzare come periferica di controllo il mouse e la tastiera (solo su piattaforma Windows) oltre che, logicamente, il pad (wired) della console. Anche se l'applicazione è stata sviluppata per Windows (dal momento che è tranquillamente compilabile su piattaforma Xbox 360 selezionando l'opportuna voce dal wizard iniziale), vediamo in primis il set di istruzioni per l'utilizzo del joypad. Una volta collegato il joypad al PC e compilata l'applicazione, gli stick analogici permetteranno di ruotare l'oggetto, il grilletto destro di aumentare la velocità di rotazione, il tasto verde A di ripristinare la vista iniziale. Innanzitutto modifichiamo il metodo Update come riportato di seguito: protected override void Update(GameTime gameTime) { if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); //Get some input UpdateInput(); //add velocity to current position modelPosition += modelVelocity; //bleed off velocity over time modelVelocity *= 0.95f; base.Update(gameTime); } Immediatamente sopra al metodo Update, aggiungiamo le seguenti stringhe: //Velocity of the model, applied each frame to the model's position Vector3 modelVelocity = Vector3.Zero; Notiamo che il metodo Update lancia una particolare funzione, UpdateInput, che di seguito andremo a definire. Per fare ciò, di seguito al metodo Draw, aggiungiamo il codice seguente: protected void UpdateInput() { //get the gamepad state GamePadState currentState = GamePad.GetState(PlayerIndex.One); if (currentState.IsConnected) { //rotate the model using the left thumbstick, scale it down modelRotation -= currentState.ThumbSticks.Left.X * 0.10f; //create some velocity if the right trigger is down Vector3 modelVelocityAdd = Vector3.Zero; //find out what direction we should be thrusting, using rotation modelVelocityAdd.X = -(float)Math.Sin(modelRotation); modelVelocityAdd.Z = -(float)Math.Cos(modelRotation); //now scale our direction by how hard the trigger is down modelVelocityAdd *= currentState.Triggers.Right; //finally, add this vector to our velocity. modelVelocity += modelVelocityAdd; GamePad.SetVibration(PlayerIndex.One, currentState.Triggers.Right, currentState.Triggers.Right); //in case you get lost, press A to warp back to the center if (currentState.Buttons.A == ButtonState.Pressed) { modelPosition = Vector3.Zero; modelVelocity = Vector3.Zero; modelRotation = 0.0f; } } } La funzione UpdateInput innanzitutto controlla che sia collegato il joypad, dopo di che assegna agli stick analogici la possibilità di ruotare l'oggetto. Le rotazioni dell'oggetto sono scalate di opportuni fattori moltiplicativi float al fine di mantenere le velocità a livelli accettabili. In seguito attraverso funzioni trigonometriche di seno e coseno, le rotazioni del modello 3D vengono associate ad un vettore (che si incrementa a seconda della pressione del grilletto destro), il quale viene sommato iterativamente al vettore precedente per ottenere il vettore velocità finale. Infine i valori delle variabili vengono riportati a 0 mediante la pressione del tasto A. Qualora non vogliate modificare i singoli metodi manualmente (cosa che suggerisco per farsi un'idea di ciò che si scrive e si modifica), il file Game1.cs integrale è riportato di seguito: #region Using Statements using System; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Storage; #endregion public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; ContentManager content; public Game1() { graphics = new GraphicsDeviceManager(this); content = new ContentManager(Services); } protected override void Initialize() { base.Initialize(); } //3d model to draw Model myModel; protected override void LoadGraphicsContent(bool loadAllContent) { if (loadAllContent) { myModel = content.Load< Model >("Content\\Models\\p1_wedge"); } } protected override void UnloadGraphicsContent(bool unloadAllContent) { if (unloadAllContent == true) { content.Unload(); } } //Velocity of the model, applied each frame to the model's position Vector3 modelVelocity = Vector3.Zero; protected override void Update(GameTime gameTime) { if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); //Get some input UpdateInput(); //add velocity to current position modelPosition += modelVelocity; //bleed off velocity over time modelVelocity *= 0.95f; base.Update(gameTime); } protected void UpdateInput() { //get the gamepad state GamePadState currentState = GamePad.GetState(PlayerIndex.One); if (currentState.IsConnected) { //rotate the model using the left thumbstick, scale it down modelRotation -= currentState.ThumbSticks.Left.X * 0.10f; //create some velocity if the right trigger is down Vector3 modelVelocityAdd = Vector3.Zero; //find out what direction we should be thrusting, using rotation modelVelocityAdd.X = -(float)Math.Sin(modelRotation); modelVelocityAdd.Z = -(float)Math.Cos(modelRotation); //now scale our direction by how hard the trigger is down modelVelocityAdd *= currentState.Triggers.Right; //finally, add this vector to our velocity. modelVelocity += modelVelocityAdd; GamePad.SetVibration(PlayerIndex.One, currentState.Triggers.Right, currentState.Triggers.Right); //in case you get lost, press A to warp back to the center if (currentState.Buttons.A == ButtonState.Pressed) { modelPosition = Vector3.Zero; modelVelocity = Vector3.Zero; modelRotation = 0.0f; } } } //Position of the model in world space, and rotation Vector3 modelPosition = Vector3.Zero; float modelRotation = 0.0f; //Position of the Camera in world space, for our view matrix Vector3 cameraPosition = new Vector3(0.0f, 50.0f, -5000.0f); //Aspect ratio to use for the projection matrix float aspectRatio = 640.0f / 480.0f; protected override void Draw(GameTime gameTime) { graphics.GraphicsDevice.Clear(Color.CornflowerBlue); //Copy any parent transforms Matrix[] transforms = new Matrix[myModel.Bones.Count]; myModel.CopyAbsoluteBoneTransformsTo(transforms); //Draw the model, a model can have multiple meshes, so loop foreach (ModelMesh mesh in myModel.Meshes) { //This is where the mesh orientation is set, as well as our camera and projection foreach (BasicEffect effect in mesh.Effects) { effect.EnableDefaultLighting(); effect.World = transforms[mesh.ParentBone.Index] * Matrix.CreateRotationY(modelRotation) * Matrix.CreateTranslation(modelPosition); effect.View = Matrix.CreateLookAt(cameraPosition, Vector3.Zero, Vector3.Up); effect.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f), aspectRatio, 1.0f, 10000.0f); } //Draw the mesh, will use the effects set above. mesh.Draw(); } base.Draw(gameTime); } }
|