/// <summary> /// Selecciona todos los colliders que estan dentro de la esfera que representa el movimiento. /// Carga la lista objetosCandidatos /// </summary> private void selectPotentialColliders(TgcElipsoid characterElipsoid, Vector3 movementVector, List<Collider> colliders) { //Dejar solo los obstáculos que están dentro del radio de movimiento del elipsoide (lo consideramos una esfera, con su mayor radio) Vector3 halfMovementVec = Vector3.Multiply(movementVector, 0.5f); movementSphere.setValues( characterElipsoid.Center + halfMovementVec, halfMovementVec.Length() + characterElipsoid.getMaxRadius() ); //Elegir todos los colliders que pasan un test Sphere-Sphere objetosCandidatos.Clear(); foreach (Collider collider in colliders) { if (collider.Enable && TgcCollisionUtils.testSphereSphere(movementSphere, collider.BoundingSphere)) { objetosCandidatos.Add(collider); } } }
public override void init() { Microsoft.DirectX.Direct3D.Device d3dDevice = GuiController.Instance.D3dDevice; //Cargar escenario específico para este ejemplo. Este escenario tiene dos layers: objetos normales y objetos con colisión a nivel de triángulo. //La colisión a nivel de triángulos es costosa. Solo debe utilizarse para objetos puntuales (como el piso). Y es recomendable dividirlo en varios //meshes (y no hacer un único piso que ocupe todo el escenario) TgcSceneLoader loader = new TgcSceneLoader(); escenario = loader.loadSceneFromFile(GuiController.Instance.ExamplesMediaDir + "\\MeshCreator\\Scenes\\Mountains\\Mountains-TgcScene.xml"); //Cargar personaje con animaciones TgcSkeletalLoader skeletalLoader = new TgcSkeletalLoader(); personaje = skeletalLoader.loadMeshAndAnimationsFromFile( GuiController.Instance.ExamplesMediaDir + "SkeletalAnimations\\BasicHuman\\" + "BasicHuman-TgcSkeletalMesh.xml", new string[] { GuiController.Instance.ExamplesMediaDir + "SkeletalAnimations\\BasicHuman\\Animations\\" + "Walk-TgcSkeletalAnim.xml", GuiController.Instance.ExamplesMediaDir + "SkeletalAnimations\\BasicHuman\\Animations\\" + "StandBy-TgcSkeletalAnim.xml", GuiController.Instance.ExamplesMediaDir + "SkeletalAnimations\\BasicHuman\\Animations\\" + "Jump-TgcSkeletalAnim.xml" }); //Configurar animacion inicial personaje.playAnimation("StandBy", true); //Escalarlo porque es muy grande personaje.Position = new Vector3(0,1000,-150); //Rotarlo 180° porque esta mirando para el otro lado personaje.rotateY(Geometry.DegreeToRadian(180f)); //BoundingSphere que va a usar el personaje personaje.AutoUpdateBoundingBox = false; characterElipsoid = new TgcElipsoid(personaje.BoundingBox.calculateBoxCenter() + new Vector3(0, 0, 0), new Vector3(12, 28, 12)); jumping = false; //Almacenar volumenes de colision del escenario objetosColisionables.Clear(); foreach (TgcMesh mesh in escenario.Meshes) { //Los objetos del layer "TriangleCollision" son colisiones a nivel de triangulo if (mesh.Layer == "TriangleCollision") { objetosColisionables.Add(TriangleMeshCollider.fromMesh(mesh)); } //El resto de los objetos son colisiones de BoundingBox. Las colisiones a nivel de triangulo son muy costosas asi que deben utilizarse solo //donde es extremadamente necesario (por ejemplo en el piso). El resto se simplifica con un BoundingBox else { objetosColisionables.Add(BoundingBoxCollider.fromBoundingBox(mesh.BoundingBox)); } } //Crear manejador de colisiones collisionManager = new ElipsoidCollisionManager(); collisionManager.GravityEnabled = true; //Crear linea para mostrar la direccion del movimiento del personaje directionArrow = new TgcArrow(); directionArrow.BodyColor = Color.Red; directionArrow.HeadColor = Color.Green; directionArrow.Thickness = 0.4f; directionArrow.HeadSize = new Vector2(5, 10); //Linea para normal de colision collisionNormalArrow = new TgcArrow(); collisionNormalArrow.BodyColor = Color.Blue; collisionNormalArrow.HeadColor = Color.Yellow; collisionNormalArrow.Thickness = 0.4f; collisionNormalArrow.HeadSize = new Vector2(2, 5); //Caja para marcar punto de colision collisionPoint = TgcBox.fromSize(new Vector3(4, 4, 4), Color.Red); //Configurar camara en Tercer Persona GuiController.Instance.ThirdPersonCamera.Enable = true; GuiController.Instance.ThirdPersonCamera.setCamera(personaje.Position, 20, -120); GuiController.Instance.ThirdPersonCamera.TargetDisplacement = new Vector3(0, 45, 0); //Crear SkyBox skyBox = new TgcSkyBox(); skyBox.Center = new Vector3(0, 0, 0); skyBox.Size = new Vector3(10000, 10000, 10000); string texturesPath = GuiController.Instance.ExamplesMediaDir + "Texturas\\Quake\\SkyBox3\\"; skyBox.setFaceTexture(TgcSkyBox.SkyFaces.Up, texturesPath + "Up.jpg"); skyBox.setFaceTexture(TgcSkyBox.SkyFaces.Down, texturesPath + "Down.jpg"); skyBox.setFaceTexture(TgcSkyBox.SkyFaces.Left, texturesPath + "Left.jpg"); skyBox.setFaceTexture(TgcSkyBox.SkyFaces.Right, texturesPath + "Right.jpg"); skyBox.setFaceTexture(TgcSkyBox.SkyFaces.Front, texturesPath + "Back.jpg"); skyBox.setFaceTexture(TgcSkyBox.SkyFaces.Back, texturesPath + "Front.jpg"); skyBox.updateValues(); //Modifier para ver BoundingBox GuiController.Instance.Modifiers.addBoolean("Collisions", "Collisions", true); GuiController.Instance.Modifiers.addBoolean("showBoundingBox", "Bouding Box", true); //Modifiers para desplazamiento del personaje GuiController.Instance.Modifiers.addFloat("VelocidadCaminar", 0, 20, 2); GuiController.Instance.Modifiers.addFloat("VelocidadRotacion", 1f, 360f, 150f); GuiController.Instance.Modifiers.addBoolean("HabilitarGravedad", "Habilitar Gravedad", true); GuiController.Instance.Modifiers.addVertex3f("Gravedad", new Vector3(-50, -50, -50), new Vector3(50, 50, 50), new Vector3(0, -4, 0)); GuiController.Instance.Modifiers.addFloat("SlideFactor", 0f, 2f, 1f); GuiController.Instance.Modifiers.addFloat("Pendiente", 0f, 1f, 0.72f); GuiController.Instance.Modifiers.addFloat("VelocidadSalto", 0f, 50f, 10f); GuiController.Instance.Modifiers.addFloat("TiempoSalto", 0f, 2f, 0.5f); GuiController.Instance.UserVars.addVar("Movement"); }
/// <summary> /// Mover Elipsoide con detección de colisiones, sliding y gravedad. /// Se actualiza la posición del centro del Elipsoide /// </summary> /// <param name="characterElipsoid">Elipsoide del cuerpo a mover</param> /// <param name="movementVector">Movimiento a realizar</param> /// <param name="colliders">Obstáculos contra los cuales se puede colisionar</param> /// <returns>Desplazamiento relativo final efecutado al Elipsoide</returns> public Vector3 moveCharacter(TgcElipsoid characterElipsoid, Vector3 movementVector, List<Collider> colliders) { //Guardar posicion original del Elipsoide Vector3 originalElipsoidCenter = characterElipsoid.Center; //Pasar elipsoid space Vector3 eCenter = TgcVectorUtils.div(characterElipsoid.Center, characterElipsoid.Radius); Vector3 eMovementVector = TgcVectorUtils.div(movementVector, characterElipsoid.Radius); eSphere.setValues(eCenter, 1); Vector3 eOrigCenter = eSphere.Center; //Ver si la distancia a recorrer es para tener en cuenta float distanceToTravelSq = movementVector.LengthSq(); if (distanceToTravelSq >= EPSILON) { //Mover la distancia pedida selectPotentialColliders(characterElipsoid, movementVector, colliders); this.result = doCollideWithWorld(eSphere, eMovementVector, characterElipsoid.Radius, objetosCandidatos, 0, movementSphere, 1); } //Aplicar gravedad if (gravityEnabled) { //Mover con gravedad Vector3 eGravity = TgcVectorUtils.div(gravityForce, characterElipsoid.Radius); selectPotentialColliders(characterElipsoid, eGravity, colliders); this.result = doCollideWithWorld(eSphere, eGravity, characterElipsoid.Radius, objetosCandidatos, 0, movementSphere, onGroundMinDotValue); } //Mover Elipsoid pasando valores de colision a R3 Vector3 movement = TgcVectorUtils.mul(eSphere.Center - eOrigCenter, characterElipsoid.Radius); characterElipsoid.moveCenter(movement); //Ajustar resultados result.realMovmentVector = TgcVectorUtils.mul(result.realMovmentVector, characterElipsoid.Radius); result.collisionPoint = TgcVectorUtils.mul(result.collisionPoint, characterElipsoid.Radius); return movement; }
public Game() { Fuentes.cargarFuentes(); //sprites if (!inicializo) { mapita = new TgcSprite(); mapita.Texture = TgcTexture.createTexture(GuiController.Instance.AlumnoEjemplosMediaDir + "\\sprites\\preview.png"); motoSprite = new TgcSprite(); motoSprite.Texture = TgcTexture.createTexture(GuiController.Instance.AlumnoEjemplosMediaDir + "\\sprites\\dirtbike.png"); timer = new TgcSprite(); timer.Texture = TgcTexture.createTexture(GuiController.Instance.AlumnoEjemplosMediaDir + "\\sprites\\gate.png"); //Ubicarlo centrado en la pantalla screenSize = GuiController.Instance.Panel3d.Size; textureSize = mapita.Texture.Size; motoTextureSize = motoSprite.Texture.Size; mapita.Scaling = (new Vector2(0.7f, 0.7f)); motoSprite.Scaling = (new Vector2(0.5f, 0.5f)); mapita.Position = new Vector2(FastMath.Max(screenSize.Width / 2 - textureSize.Width * 0.7f / 2, 0), 16); motoSprite.Position = new Vector2(FastMath.Max(screenSize.Width / 2 - motoTextureSize.Width * 0.5f / 2 - textureSize.Width * 0.7f / 2, 0), 8); timer.Position = new Vector2(screenSize.Width - 250, screenSize.Height - 125); timer.Scaling = new Vector2(0.9f, 0.8f); posMotoInicial = motoSprite.Position; inicializo = true; } d3dDevice = GuiController.Instance.D3dDevice; d3dDevice.Transform.Projection = Matrix.PerspectiveFovLH(Geometry.DegreeToRadian(45.0f), TgcD3dDevice.aspectRatio, 1f, 5000000f); string texturesPath = GuiController.Instance.AlumnoEjemplosMediaDir + "skybox\\"; TgcSceneLoader loader = new TgcSceneLoader(); collisionManager = new ElipsoidCollisionManager(); collisionManager.GravityEnabled = false; tiempoAcelerando = 0f; tiempoDescelerando = 0f; velIni = 0f; tocandoPiso = false; saltando = true; ultimoMov = new Vector3(0, 0, 0); //skybox inicializarSkybox(texturesPath); //checkpoints int posCP = -150; foreach (TgcBoundingBox bb in checkpoints) { bb.setExtremes(new Vector3(-200, -100, posCP), new Vector3(200, 1000, posCP - 10)); posCP -= 1300; } //carga la ciudad scene = loader.loadSceneFromFile(GuiController.Instance.AlumnoEjemplosMediaDir + "pistaDesierto\\pistaDesierto2-TgcScene.xml"); //cargo la moto motorcycle = loader.loadSceneFromFile(GuiController.Instance.AlumnoEjemplosMediaDir + "moto\\Moto2-TgcScene.xml").Meshes[0]; motorcycle.move(-40, 100, -150); //cargo la piramide piramid = loader.loadSceneFromFile(GuiController.Instance.AlumnoEjemplosMediaDir + "piramide\\piramide-TgcScene.xml").Meshes[0]; piramid.Scale = new Vector3(5, 5, 5); piramid.move(-265, -45, -13750); //cargo texto ganaste textGanaste = new TgcText2d(); textGanaste2 = new TgcText2d(); //Cargar Textos textGanaste.Text = "FELICIDADES, HAS GANADO"; textGanaste2.Text = "APRETE Q PARA VOLVER AL MENU"; textGanaste.Position = new Point(0, 50); textGanaste2.Position = new Point(0, 100); textGanaste.changeFont(new System.Drawing.Font("TimesNewRoman", 23, FontStyle.Bold | FontStyle.Bold)); textGanaste2.changeFont(new System.Drawing.Font("TimesNewRoman", 23, FontStyle.Bold | FontStyle.Bold)); textGanaste.Color = Color.White; textGanaste2.Color = Color.White; // Creo texto contador de tiempo textoContadorTiempo = new TgcText2d(); textoContadorTiempo.Color = Color.Black; textoContadorTiempo.Align = TgcText2d.TextAlign.RIGHT; textoContadorTiempo.Position = new Point(630, 400); //(680, 400) textoContadorTiempo.Size = new Size(300, 100); textoContadorTiempo.changeFont(new System.Drawing.Font(Fuentes.fuente.Families[0], 25, FontStyle.Regular)); // Creo texto mejor tiempo textoMejorTiempo = new TgcText2d(); textoMejorTiempo.Color = Color.Black; textoMejorTiempo.Align = TgcText2d.TextAlign.RIGHT; textoMejorTiempo.Position = new Point(630, 430); //(680, 430) textoMejorTiempo.Size = new Size(300, 100); textoMejorTiempo.changeFont(new System.Drawing.Font(Fuentes.fuente.Families[0], 25, FontStyle.Regular)); //Texto para mostrar fps textFPS = new TgcText2d(); textFPS.Position = new Point((screenSize.Width / (-2)), 0); textFPS.Text = "FPS: "; textFPS.Color = Color.Yellow; //camara GuiController.Instance.ThirdPersonCamera.Enable = true; GuiController.Instance.ThirdPersonCamera.setCamera(motorcycle.Position + new Vector3(0,0,-100), 10, 200); GuiController.Instance.ThirdPersonCamera.rotateY(-0.7f); //creo la bounding elipsoid motorcycle.Scale = new Vector3(0.5f, 0.5f, 0.5f); // motorcycle.AutoUpdateBoundingBox = false; characterElipsoid = new TgcElipsoid(motorcycle.BoundingBox.calculateBoxCenter() + new Vector3(0, 0, 0), new Vector3(23, 23, 23) * 0.5f); //cargo los colliders objetosColisionables.Clear(); foreach (TgcMesh mesh in scene.Meshes) { //Los objetos del layer "TriangleCollision" son colisiones a nivel de triangulo if (mesh.Layer == "TriangleCollision") { objetosColisionables.Add(TriangleMeshCollider.fromMesh(mesh)); } //El resto de los objetos son colisiones de BoundingBox. Las colisiones a nivel de triangulo son muy costosas asi que deben utilizarse solo //donde es extremadamente necesario (por ejemplo en el piso). El resto se simplifica con un BoundingBox else { objetosColisionables.Add(BoundingBoxCollider.fromBoundingBox(mesh.BoundingBox)); } } //agrego Piramide Como objeto Colisionable objetosColisionables.Add(BoundingBoxCollider.fromBoundingBox(piramid.BoundingBox)); //Cargo lineaInicio lineaInicio = new TgcBox(); lineaInicio.Position = new Vector3(-7, 30, -50); lineaInicio.Size = new Vector3(200, 2000, 1); lineaInicio.updateValues(); //Cargo lineaFin lineaFin = new TgcBox(); lineaFin.Size = new Vector3(100, 1000, 1); lineaFin.Position = new Vector3(0, 15, -13250); lineaFin.Color = Color.White; lineaFin.updateValues(); //La agrego como objeto colisionable objetosColisionables.Add(BoundingBoxCollider.fromBoundingBox(lineaInicio.BoundingBox)); showBB = false; //iluminacion ojalaQueAnde = new ShadowMap(scene, motorcycle); //DEBUG //Crear linea para mostrar la direccion del movimiento del personaje directionArrow = new TgcArrow(); directionArrow.BodyColor = Color.Red; directionArrow.HeadColor = Color.Green; directionArrow.Thickness = 0.4f; directionArrow.HeadSize = new Vector2(5, 10); //Linea para normal de colision collisionNormalArrow = new TgcArrow(); collisionNormalArrow.BodyColor = Color.Blue; collisionNormalArrow.HeadColor = Color.Yellow; collisionNormalArrow.Thickness = 0.4f; collisionNormalArrow.HeadSize = new Vector2(2, 5); //Caja para marcar punto de colision collisionPoint = TgcBox.fromSize(new Vector3(4, 4, 4), Color.Red); //TERMINA DEBUG }