public void Fire(Vector3Df position, Vector3Df direction, uint time) { Shot s = new Shot(); s.direction = direction; Vector3Df e = position + s.direction * worldInfinity; Line3Df l = new Line3Df(position, e); Vector3Df cv; Triangle3Df ct; SceneNode cn; if (sceneManager.SceneCollisionManager.GetCollisionPoint(l, worldTriangles, out cv, out ct, out cn)) { e = cv; } s.deathTime = time + (uint)((e - position).Length / shotSpeed); s.node = sceneManager.AddSphereSceneNode(10); s.node.SetMaterialFlag(MaterialFlag.Lighting, false); sceneManager.MeshManipulator.SetVertexColors(((MeshSceneNode)s.node).Mesh, Color.OpaqueWhite); s.node.AddAnimator(sceneManager.CreateFlyStraightAnimator(position, e, (s.deathTime - time) / 1000.0f)); s.node.AnimatorList[0].Drop(); sceneManager.AddLightSceneNode(s.node); shots.Add(s); }
public void MouseClick(int x, int y, bool isRight) { if (m_state != State.Playing) { return; } Vector2Di m = new Vector2Di(x, y); Line3Df l = m_device.SceneManager.SceneCollisionManager.GetRayFromScreenCoordinates(m); SceneNode n = m_device.SceneManager.SceneCollisionManager.GetSceneNodeFromRayBB(l, 0x10000, m_root); if (n != null && n.ID >= 0x10000) { int i = n.ID - 0x10000; if (isRight) { flagCell(m_board[i]); } else { revealCell(m_board[i]); } } }
public void Fire(Vector3Df position, Vector3Df direction, uint time) { Shot s = new Shot(); s.direction = direction; Vector3Df e = position + s.direction * worldInfinity; Line3Df l = new Line3Df(position, e); Vector3Df cv; Triangle3Df ct; SceneNode cn; if (sceneManager.SceneCollisionManager.GetCollisionPoint(l, worldTriangles, out cv, out ct, out cn)) e = cv; s.deathTime = time + (uint)((e - position).Length / shotSpeed); s.node = sceneManager.AddSphereSceneNode(10); s.node.SetMaterialFlag(MaterialFlag.Lighting, false); sceneManager.MeshManipulator.SetVertexColors(((MeshSceneNode)s.node).Mesh, Color.OpaqueWhite); s.node.AddAnimator(sceneManager.CreateFlyStraightAnimator(position, e, (s.deathTime - time) / 1000.0f)); s.node.AnimatorList[0].Drop(); sceneManager.AddLightSceneNode(s.node); shots.Add(s); }
static bool device_OnEvent(Event evnt) { if (evnt.Type == EventType.Mouse && evnt.Mouse.Type == MouseEventType.RightDown) { Vector3Df v; Triangle3Df t; SceneNode n; Line3Df l = scene.SceneCollisionManager.GetRayFromScreenCoordinates(new Vector2Di(evnt.Mouse.X, evnt.Mouse.Y)); if (scene.SceneCollisionManager.GetCollisionPoint(l, sphere.TriangleSelector, out v, out t, out n)) { path.AddPoint(v); return(true); } } if (evnt.Type == EventType.Key) { switch (evnt.Key.Key) { case KeyCode.Left: camera.Inclination++; return(true); case KeyCode.Right: camera.Inclination--; return(true); case KeyCode.Up: camera.Azimuth--; return(true); case KeyCode.Down: camera.Azimuth++; return(true); case KeyCode.KeyC: path.Clear(); return(true); //case KeyCode.KeyS: // path.Save("../../media/SphereCameraPath.xml"); // return true; case KeyCode.KeyR: path.Load("../../media/SphereCameraPath.xml"); return(true); } } return(false); }
public Triangle3Df interpolateFrom2D(Vector2Di input) { //We can assume two things: //That the hand will be considered in front of the object //And that the hand will always be orbiting around the object //So we calculate based off of sin and cos and relative positions SceneCollisionManager collisionManager = device.SceneManager.SceneCollisionManager; Line3Df ray = device.SceneManager.SceneCollisionManager.GetRayFromScreenCoordinates(input); //calcLine.End = calcLine.End.Normalize(); //calcLine.End *= new Vector3Df(20); // Tracks the current intersection point with the level or a mesh Vector3Df intersection; // Used to show with triangle has been hit Triangle3Df hitTriangle; SceneNode selectedSceneNode = device.SceneManager.SceneCollisionManager.GetSceneNodeAndCollisionPointFromRay( ray, out intersection, // This will be the position of the collision out hitTriangle); // This ensures that only nodes that we have set up to be pickable are considered SceneNode highlightedSceneNode = null; // If the ray hit anything, move the billboard to the collision position // and draw the triangle that was hit. if (selectedSceneNode != null) { //bill.Position = new Vector3Df(intersection); // We need to reset the transform before doing our own rendering. device.VideoDriver.SetTransform(TransformationState.World, new Matrix()); //device.VideoDriver.SetMaterial(material); device.VideoDriver.Draw3DTriangle(hitTriangle, new Color(255, 255, 0, 0)); // We can check the flags for the scene node that was hit to see if it should be // highlighted. The animated nodes can be highlighted, but not the Quake level mesh highlightedSceneNode = selectedSceneNode; // Highlighting in this case means turning lighting OFF for this node, // which means that it will be drawn with full brightness. //highlightedSceneNode.SetMaterialFlag(MaterialFlag.Lighting, false); } return(hitTriangle); }
private void irrlichtPanel_MouseClick(object sender, MouseEventArgs e) { // need to have a click plus the ctrl key down if (pickKeyDown) { ViewFrustum f = smgr.ActiveCamera.ViewFrustum; Vector3Df farLeftUp = f.FarLeftUp; Vector3Df lefttoright = f.FarRightUp - farLeftUp; Vector3Df uptodown = f.FarLeftDown - farLeftUp; float dx = e.X / (float)viewPort.Width; float dy = e.Y / (float)viewPort.Height; Line3Df ray = new Line3Df(f.CameraPosition, farLeftUp + (lefttoright * dx) + (uptodown * dy)); SceneNode pickedNode = smgr.SceneCollisionManager.GetSceneNodeFromRayBB(ray); if (pickedNode != null) { RenderMessage message = new RenderMessage(MessageType.HIGHLIGHT_NODE, pickedNode); commandQueue.Enqueue(message); propertiesDlg.SetProperties(pickedNode); if (!propertiesDlg.Visible) { propertiesDlg.Show(this); } if (backgroundSearcher.IsBusy) { backgroundSearcher.CancelAsync(); } backgroundSearcher.RunWorkerAsync(pickedNode.ID); } } }
static bool device_OnEvent(Event evnt) { if (evnt.Type == EventType.Mouse && evnt.Mouse.Type == MouseEventType.Move) { Vector2Di m = new Vector2Di(evnt.Mouse.X, evnt.Mouse.Y); Line3Df l = device.SceneManager.SceneCollisionManager.GetRayFromScreenCoordinates(m); Plane3Df p = new Plane3Df(new Vector3Df(0, 0, 0), new Vector3Df(100, 0, 0), new Vector3Df(0, 0, 100)); Vector3Df i = p.GetIntersectionWithLimitedLine(l.Start, l.End); if (i != null) { camera.Target = game.CenterOfTheBoard + new Vector3Df( (m.Y - device.VideoDriver.ScreenSize.Height / 2) / 100.0f, 0, (m.X - device.VideoDriver.ScreenSize.Width / 2) / 100.0f); i.Y += 25; // we want light to be a little bit above light.Position = i; } } if (window == null && evnt.Type == EventType.Mouse && (evnt.Mouse.Type == MouseEventType.LeftDown || evnt.Mouse.Type == MouseEventType.RightDown)) { text.Visible = false; // if user started to play - remove the gui text game.MouseClick(evnt.Mouse.X, evnt.Mouse.Y, evnt.Mouse.Type == MouseEventType.RightDown); if (game.StateOfTheGame != Game.State.Playing) { text.Visible = true; text.Text = game.StateOfTheGame == Game.State.Won ? TextWon : TextLost; } return(true); } if (evnt.Type == EventType.Key && evnt.Key.PressedDown && evnt.Key.Key == KeyCode.Esc) { if (window != null) { window.Remove(); window = null; return(true); } GUIEnvironment gui = device.GUIEnvironment; window = gui.AddWindow(new Recti(100, 100, 400, 400), true, "GAME MENU"); gui.AddButton(new Recti(20, 40, window.ClientRect.Width - 20, 60), window, 1510, "NEW GAME 5x5"); gui.AddButton(new Recti(20, 60, window.ClientRect.Width - 20, 80), window, 1520, "NEW GAME 10x10"); gui.AddButton(new Recti(20, 80, window.ClientRect.Width - 20, 100), window, 1530, "NEW GAME 15x15"); gui.AddButton(new Recti(20, 100, window.ClientRect.Width - 20, 120), window, 1540, "NEW GAME 20x20"); gui.AddCheckBox(optionShadows, new Recti(20, 140, window.ClientRect.Width - 20, 160), "SHOW REALTIME SHADOWS", window, 1710); gui.AddCheckBox(optionBackground, new Recti(20, 160, window.ClientRect.Width - 20, 180), "SHOW BACKGROUND", window, 1720); gui.AddCheckBox(optionFPS, new Recti(20, 180, window.ClientRect.Width - 20, 200), "SHOW FPS", window, 1730); gui.AddButton(new Recti(20, 260, window.ClientRect.Width - 20, 280), window, 1590, "EXIT GAME"); return(true); } if (window != null && evnt.Type == EventType.GUI) { if (evnt.GUI.Caller == window && evnt.GUI.Type == GUIEventType.ElementClosed) { window.Remove(); window = null; return(true); } if (evnt.GUI.Caller.ID == 1510 && evnt.GUI.Type == GUIEventType.ButtonClicked) { window.Remove(); window = null; game.NewGame(5, 5); setupCameraPositionAndTarget(); return(true); } if (evnt.GUI.Caller.ID == 1520 && evnt.GUI.Type == GUIEventType.ButtonClicked) { window.Remove(); window = null; game.NewGame(10, 10); setupCameraPositionAndTarget(); return(true); } if (evnt.GUI.Caller.ID == 1530 && evnt.GUI.Type == GUIEventType.ButtonClicked) { window.Remove(); window = null; game.NewGame(15, 15); setupCameraPositionAndTarget(); return(true); } if (evnt.GUI.Caller.ID == 1540 && evnt.GUI.Type == GUIEventType.ButtonClicked) { window.Remove(); window = null; game.NewGame(20, 20); setupCameraPositionAndTarget(); return(true); } if (evnt.GUI.Caller.ID == 1590 && evnt.GUI.Type == GUIEventType.ButtonClicked) { device.Close(); return(true); } if (evnt.GUI.Caller.ID == 1710 && evnt.GUI.Type == GUIEventType.CheckBoxChanged) { optionShadows = (evnt.GUI.Caller as GUICheckBox).Checked; light.CastShadows = optionShadows; return(true); } if (evnt.GUI.Caller.ID == 1720 && evnt.GUI.Type == GUIEventType.CheckBoxChanged) { optionBackground = (evnt.GUI.Caller as GUICheckBox).Checked; device.SceneManager.GetSceneNodeFromID(7777).Visible = optionBackground; return(true); } if (evnt.GUI.Caller.ID == 1730 && evnt.GUI.Type == GUIEventType.CheckBoxChanged) { optionFPS = (evnt.GUI.Caller as GUICheckBox).Checked; return(true); } } return(false); }
static void Main(string[] args) { // Initialize device. DriverType driverType; if (!AskUserForDriver(out driverType)) { return; } IrrlichtDevice device = IrrlichtDevice.CreateDevice(driverType, new Dimension2Di(640, 480)); if (device == null) { return; } // Add event handling. device.OnEvent += new IrrlichtDevice.EventHandler(device_OnEvent); // Save important pointers. VideoDriver driver = device.VideoDriver; SceneManager smgr = device.SceneManager; Logger logger = device.Logger; // Initialize joysticks and print info about them. List <JoystickInfo> joystickList = device.ActivateJoysticks(); if (joystickList != null) { logger.Log("Joystick support is enabled and " + joystickList.Count.ToString() + " joystick(s) are present."); foreach (JoystickInfo j in joystickList) { logger.Log("Joystick " + j.Joystick.ToString() + ":"); logger.Log("\tName: \"" + j.Name + "\""); logger.Log("\tAxisCount: " + j.AxisCount.ToString()); logger.Log("\tButtonCount: " + j.ButtonCount.ToString()); logger.Log("\tPovHat: " + j.PovHat.ToString()); } } else { logger.Log("Joystick support is not enabled."); } device.SetWindowCaption("Mouse and joystick - Irrlicht Lime - " + joystickList.Count.ToString() + " joystick(s)"); // Create an arrow mesh and move it around either with the joystick axis/hat, // or make it follow the mouse pointer (when no joystick movement). SceneNode node = smgr.AddMeshSceneNode( smgr.AddArrowMesh( "Arrow", new Color(255, 0, 0), new Color(0, 255, 0), 16, 16, 2.0f, 1.3f, 0.1f, 0.6f ) ); node.SetMaterialFlag(MaterialFlag.Lighting, false); CameraSceneNode camera = smgr.AddCameraSceneNode(); camera.Position = new Vector3Df(0, 0, -10); // As in example #4, we'll use framerate independent movement. uint then = device.Timer.Time; const float MovementSpeed = 5.0f; // Run main cycle. while (device.Run()) { // Work out a frame delta time. uint now = device.Timer.Time; float frameDeltaTime = (float)(now - then) / 1000.0f; // in seconds then = now; bool movedWithJoystick = false; Vector3Df nodePosition = node.Position; if (joystickList.Count > 0) { float moveHorizontal = 0.0f; // range is -1.0 for full left to +1.0 for full right float moveVertical = 0.0f; // range is -1.0 for full down to +1.0 for full up // We receive the full analog range of the axes, and so have to implement our own dead zone. // This is an empirical value, since some joysticks have more jitter or creep around the center // point than others. We'll use 5% of the range as the dead zone, but generally you would want // to give the user the option to change this. float DeadZone = 0.05f; moveHorizontal = joystickState.Axis[0] / 32767.0f; // "0" for X axis if (Math.Abs(moveHorizontal) < DeadZone) { moveHorizontal = 0.0f; } moveVertical = joystickState.Axis[1] / -32767.0f; // "1" for Y axis if (Math.Abs(moveVertical) < DeadZone) { moveVertical = 0.0f; } // POV will contain 65535 if POV hat info no0t supported, so we can check its range. ushort povDegrees = (ushort)(joystickState.POV / 100); if (povDegrees < 360) { if (povDegrees > 0 && povDegrees < 180) { moveHorizontal = +1.0f; } else if (povDegrees > 180) { moveHorizontal = -1.0f; } if (povDegrees > 90 && povDegrees < 270) { moveVertical = -1.0f; } else if (povDegrees > 270 || povDegrees < 90) { moveVertical = +1.0f; } } // If we have any movement, apply it. if (Math.Abs(moveHorizontal) > 0.0001f || Math.Abs(moveVertical) > 0.0001f) { float m = frameDeltaTime * MovementSpeed; nodePosition = new Vector3Df(moveHorizontal * m, moveVertical * m, nodePosition.Z); movedWithJoystick = true; } } // If the arrow node isn't being moved with the joystick, then have it follow the mouse cursor. if (!movedWithJoystick) { // Create a ray through the mouse cursor. Line3Df ray = smgr.SceneCollisionManager.GetRayFromScreenCoordinates(mouseState.Position, camera); // And intersect the ray with a plane around the node facing towards the camera. Plane3Df plane = new Plane3Df(nodePosition, new Vector3Df(0, 0, -1)); Vector3Df mousePosition; if (plane.GetIntersectionWithLine(ray.Start, ray.Vector, out mousePosition)) { // We now have a mouse position in 3d space; move towards it. Vector3Df toMousePosition = mousePosition - nodePosition; float availableMovement = frameDeltaTime * MovementSpeed; if (toMousePosition.Length <= availableMovement) { nodePosition = mousePosition; // jump to the final position } else { nodePosition += toMousePosition.Normalize() * availableMovement; // move towards it } } } node.Position = nodePosition; // Turn lighting on and off depending on whether the left mouse button is down. node.SetMaterialFlag(MaterialFlag.Lighting, mouseState.IsLeftButtonDown); // Draw all. driver.BeginScene(true, true, new Color(113, 113, 133)); smgr.DrawAll(); driver.EndScene(); } // Drop the device. device.Drop(); }
static void Main() { DriverType?driverType = AskForDriver(); if (!driverType.HasValue) { return; } IrrlichtDevice device = IrrlichtDevice.CreateDevice(driverType.Value, new Dimension2Di(640, 480)); if (device == null) { return; } VideoDriver driver = device.VideoDriver; SceneManager smgr = device.SceneManager; device.FileSystem.AddFileArchive("../../media/map-20kdm2.pk3"); AnimatedMesh q3levelmesh = smgr.GetMesh("20kdm2.bsp"); MeshSceneNode q3node = null; // The Quake mesh is pickable, but doesn't get highlighted. if (q3levelmesh != null) { q3node = smgr.AddOctreeSceneNode(q3levelmesh.GetMesh(0), null, IDFlag_IsPickable); } TriangleSelector selector = null; if (q3node != null) { q3node.Position = new Vector3Df(-1350, -130, -1400); selector = smgr.CreateOctreeTriangleSelector(q3node.Mesh, q3node, 128); q3node.TriangleSelector = selector; // We're not done with this selector yet, so don't drop it. } // Set a jump speed of 3 units per second, which gives a fairly realistic jump // when used with the gravity of (0, -1000, 0) in the collision response animator. CameraSceneNode camera = smgr.AddCameraSceneNodeFPS(null, 100.0f, 0.3f, ID_IsNotPickable, null, true, 3.0f); camera.Position = new Vector3Df(50, 50, -60); camera.Target = new Vector3Df(-70, 30, -60); if (selector != null) { SceneNodeAnimator anim = smgr.CreateCollisionResponseAnimator( selector, camera, new Vector3Df(30, 50, 30), new Vector3Df(0, -1000, 0), new Vector3Df(0, 30, 0)); selector.Drop(); // As soon as we're done with the selector, drop it. camera.AddAnimator(anim); anim.Drop(); // And likewise, drop the animator when we're done referring to it. } // Now I create three animated characters which we can pick, a dynamic light for // lighting them, and a billboard for drawing where we found an intersection. // First, let's get rid of the mouse cursor. We'll use a billboard to show what we're looking at. device.CursorControl.Visible = false; // Add the billboard. BillboardSceneNode bill = smgr.AddBillboardSceneNode(); bill.SetMaterialType(MaterialType.TransparentAddColor); bill.SetMaterialTexture(0, driver.GetTexture("../../media/particle.bmp")); bill.SetMaterialFlag(MaterialFlag.Lighting, false); bill.SetMaterialFlag(MaterialFlag.ZBuffer, false); bill.SetSize(20, 20, 20); bill.ID = ID_IsNotPickable; // This ensures that we don't accidentally ray-pick it AnimatedMeshSceneNode node = null; // Add an MD2 node, which uses vertex-based animation. node = smgr.AddAnimatedMeshSceneNode(smgr.GetMesh("../../media/faerie.md2"), null, IDFlag_IsPickable | IDFlag_IsHighlightable); node.Position = new Vector3Df(-90, -15, -140); // Put its feet on the floor. node.Scale = new Vector3Df(1.6f); // Make it appear realistically scaled node.SetMD2Animation(AnimationTypeMD2.Point); node.AnimationSpeed = 20.0f; node.GetMaterial(0).SetTexture(0, driver.GetTexture("../../media/faerie2.bmp")); node.GetMaterial(0).Lighting = true; node.GetMaterial(0).NormalizeNormals = true; // Now create a triangle selector for it. The selector will know that it // is associated with an animated node, and will update itself as necessary. selector = smgr.CreateTriangleSelector(node); node.TriangleSelector = selector; selector.Drop(); // We're done with this selector, so drop it now. // And this B3D file uses skinned skeletal animation. node = smgr.AddAnimatedMeshSceneNode(smgr.GetMesh("../../media/ninja.b3d"), null, IDFlag_IsPickable | IDFlag_IsHighlightable); node.Scale = new Vector3Df(10); node.Position = new Vector3Df(-75, -66, -80); node.Rotation = new Vector3Df(0, 90, 0); node.AnimationSpeed = 8.0f; node.GetMaterial(0).NormalizeNormals = true; // Just do the same as we did above. selector = smgr.CreateTriangleSelector(node); node.TriangleSelector = selector; selector.Drop(); // This X files uses skeletal animation, but without skinning. node = smgr.AddAnimatedMeshSceneNode(smgr.GetMesh("../../media/dwarf.x"), null, IDFlag_IsPickable | IDFlag_IsHighlightable); node.Position = new Vector3Df(-70, -66, -30); // Put its feet on the floor. node.Rotation = new Vector3Df(0, -90, 0); // And turn it towards the camera. node.AnimationSpeed = 20.0f; selector = smgr.CreateTriangleSelector(node); node.TriangleSelector = selector; selector.Drop(); // And this mdl file uses skinned skeletal animation. node = smgr.AddAnimatedMeshSceneNode(smgr.GetMesh("../../media/yodan.mdl"), null, IDFlag_IsPickable | IDFlag_IsHighlightable); node.Position = new Vector3Df(-90, -25, 20); node.Scale = new Vector3Df(0.8f); node.GetMaterial(0).Lighting = true; node.AnimationSpeed = 20.0f; // Just do the same as we did above. selector = smgr.CreateTriangleSelector(node); node.TriangleSelector = selector; selector.Drop(); // Add a light, so that the unselected nodes aren't completely dark. LightSceneNode light = smgr.AddLightSceneNode(null, new Vector3Df(-60, 100, 400), new Colorf(1.0f, 1.0f, 1.0f), 600.0f); light.ID = ID_IsNotPickable; // Make it an invalid target for selection. // Remember which scene node is highlighted SceneNode highlightedSceneNode = null; SceneCollisionManager collMan = smgr.SceneCollisionManager; int lastFPS = -1; // draw the selection triangle only as wireframe Material material = new Material(); material.Lighting = false; material.Wireframe = true; while (device.Run()) { if (device.WindowActive) { driver.BeginScene(ClearBufferFlag.All, new Color(0)); smgr.DrawAll(); // Unlight any currently highlighted scene node if (highlightedSceneNode != null) { highlightedSceneNode.SetMaterialFlag(MaterialFlag.Lighting, true); highlightedSceneNode = null; } // All intersections in this example are done with a ray cast out from the camera to // a distance of 1000. You can easily modify this to check (e.g.) a bullet // trajectory or a sword's position, or create a ray from a mouse click position using // collMan.GetRayFromScreenCoordinates() Line3Df ray = new Line3Df(); ray.Start = camera.Position; ray.End = ray.Start + (camera.Target - ray.Start).Normalize() * 1000.0f; // This call is all you need to perform ray/triangle collision on every scene node // that has a triangle selector, including the Quake level mesh. It finds the nearest // collision point/triangle, and returns the scene node containing that point. // Irrlicht provides other types of selection, including ray/triangle selector, // ray/box and ellipse/triangle selector, plus associated helpers. // See the methods of ISceneCollisionManager SceneNode selectedSceneNode = collMan.GetSceneNodeAndCollisionPointFromRay( ray, out Vector3Df intersection, // This will be the position of the collision out Triangle3Df hitTriangle, // This will be the triangle hit in the collision IDFlag_IsPickable); // This ensures that only nodes that we have set up to be pickable are considered // If the ray hit anything, move the billboard to the collision position // and draw the triangle that was hit. if (selectedSceneNode != null) { bill.Position = intersection; // We need to reset the transform before doing our own rendering. driver.SetTransform(TransformationState.World, Matrix.Identity); driver.SetMaterial(material); driver.Draw3DTriangle(hitTriangle, new Color(255, 0, 0)); // We can check the flags for the scene node that was hit to see if it should be // highlighted. The animated nodes can be highlighted, but not the Quake level mesh if ((selectedSceneNode.ID & IDFlag_IsHighlightable) == IDFlag_IsHighlightable) { highlightedSceneNode = selectedSceneNode; // Highlighting in this case means turning lighting OFF for this node, // which means that it will be drawn with full brightness. highlightedSceneNode.SetMaterialFlag(MaterialFlag.Lighting, false); } } // We're all done drawing, so end the scene. driver.EndScene(); int fps = driver.FPS; if (lastFPS != fps) { device.SetWindowCaption(String.Format( "Collision detection example - Irrlicht Engine [{0}] fps: {1}", driver.Name, fps)); lastFPS = fps; } } } device.Drop(); }
static void Main(string[] args) { DriverType driverType; if (!AskUserForDriver(out driverType)) return; IrrlichtDevice device = IrrlichtDevice.CreateDevice(driverType, new Dimension2Di(640, 480)); if (device == null) return; VideoDriver driver = device.VideoDriver; SceneManager smgr = device.SceneManager; device.FileSystem.AddFileArchive("../../media/map-20kdm2.pk3"); AnimatedMesh q3levelmesh = smgr.GetMesh("20kdm2.bsp"); MeshSceneNode q3node = null; // The Quake mesh is pickable, but doesn't get highlighted. if (q3levelmesh != null) q3node = smgr.AddOctreeSceneNode(q3levelmesh.GetMesh(0), null, IDFlag_IsPickable); TriangleSelector selector = null; if (q3node != null) { q3node.Position = new Vector3Df(-1350, -130, -1400); selector = smgr.CreateOctreeTriangleSelector(q3node.Mesh, q3node, 128); q3node.TriangleSelector = selector; // We're not done with this selector yet, so don't drop it. } // Set a jump speed of 3 units per second, which gives a fairly realistic jump // when used with the gravity of (0, -10, 0) in the collision response animator. CameraSceneNode camera = smgr.AddCameraSceneNodeFPS(null, 100.0f, 0.3f, ID_IsNotPickable, null, true, 3.0f); camera.Position = new Vector3Df(50, 50, -60); camera.Target = new Vector3Df(-70, 30, -60); if (selector != null) { SceneNodeAnimator anim = smgr.CreateCollisionResponseAnimator( selector, camera, new Vector3Df(30, 50, 30), new Vector3Df(0, -10, 0), new Vector3Df(0, 30, 0)); selector.Drop(); // As soon as we're done with the selector, drop it. camera.AddAnimator(anim); anim.Drop(); // And likewise, drop the animator when we're done referring to it. } // Now I create three animated characters which we can pick, a dynamic light for // lighting them, and a billboard for drawing where we found an intersection. // First, let's get rid of the mouse cursor. We'll use a billboard to show what we're looking at. device.CursorControl.Visible = false; // Add the billboard. BillboardSceneNode bill = smgr.AddBillboardSceneNode(); bill.SetMaterialType(MaterialType.TransparentAddColor); bill.SetMaterialTexture(0, driver.GetTexture("../../media/particle.bmp")); bill.SetMaterialFlag(MaterialFlag.Lighting, false); bill.SetMaterialFlag(MaterialFlag.ZBuffer, false); bill.SetSize(20, 20, 20); bill.ID = ID_IsNotPickable; // This ensures that we don't accidentally ray-pick it AnimatedMeshSceneNode node = null; // Add an MD2 node, which uses vertex-based animation. node = smgr.AddAnimatedMeshSceneNode(smgr.GetMesh("../../media/faerie.md2"), null, IDFlag_IsPickable | IDFlag_IsHighlightable); node.Position = new Vector3Df(-90, -15, -140); // Put its feet on the floor. node.Scale = new Vector3Df(1.6f); // Make it appear realistically scaled node.SetMD2Animation(AnimationTypeMD2.Point); node.AnimationSpeed = 20.0f; node.GetMaterial(0).SetTexture(0, driver.GetTexture("../../media/faerie2.bmp")); node.GetMaterial(0).Lighting = true; node.GetMaterial(0).NormalizeNormals = true; // Now create a triangle selector for it. The selector will know that it // is associated with an animated node, and will update itself as necessary. selector = smgr.CreateTriangleSelector(node); node.TriangleSelector = selector; selector.Drop(); // We're done with this selector, so drop it now. // And this B3D file uses skinned skeletal animation. node = smgr.AddAnimatedMeshSceneNode(smgr.GetMesh("../../media/ninja.b3d"), null, IDFlag_IsPickable | IDFlag_IsHighlightable); node.Scale = new Vector3Df(10); node.Position = new Vector3Df(-75, -66, -80); node.Rotation = new Vector3Df(0, 90, 0); node.AnimationSpeed = 8.0f; node.GetMaterial(0).NormalizeNormals = true; // Just do the same as we did above. selector = smgr.CreateTriangleSelector(node); node.TriangleSelector = selector; selector.Drop(); // This X files uses skeletal animation, but without skinning. node = smgr.AddAnimatedMeshSceneNode(smgr.GetMesh("../../media/dwarf.x"), null, IDFlag_IsPickable | IDFlag_IsHighlightable); node.Position = new Vector3Df(-70, -66, -30); // Put its feet on the floor. node.Rotation = new Vector3Df(0, -90, 0); // And turn it towards the camera. node.AnimationSpeed = 20.0f; selector = smgr.CreateTriangleSelector(node); node.TriangleSelector = selector; selector.Drop(); // And this mdl file uses skinned skeletal animation. node = smgr.AddAnimatedMeshSceneNode(smgr.GetMesh("../../media/yodan.mdl"), null, IDFlag_IsPickable | IDFlag_IsHighlightable); node.Position = new Vector3Df(-90, -25, 20); node.Scale = new Vector3Df(0.8f); node.GetMaterial(0).Lighting = true; node.AnimationSpeed = 20.0f; // Just do the same as we did above. selector = smgr.CreateTriangleSelector(node); node.TriangleSelector = selector; selector.Drop(); // Add a light, so that the unselected nodes aren't completely dark. LightSceneNode light = smgr.AddLightSceneNode(null, new Vector3Df(-60, 100, 400), new Colorf(1.0f, 1.0f, 1.0f), 600.0f); light.ID = ID_IsNotPickable; // Make it an invalid target for selection. // Remember which scene node is highlighted SceneNode highlightedSceneNode = null; SceneCollisionManager collMan = smgr.SceneCollisionManager; int lastFPS = -1; // draw the selection triangle only as wireframe Material material = new Material(); material.Lighting = false; material.Wireframe = true; while (device.Run()) if (device.WindowActive) { driver.BeginScene(true, true, new Color(0)); smgr.DrawAll(); // Unlight any currently highlighted scene node if (highlightedSceneNode != null) { highlightedSceneNode.SetMaterialFlag(MaterialFlag.Lighting, true); highlightedSceneNode = null; } // All intersections in this example are done with a ray cast out from the camera to // a distance of 1000. You can easily modify this to check (e.g.) a bullet // trajectory or a sword's position, or create a ray from a mouse click position using // ISceneCollisionManager::getRayFromScreenCoordinates() Line3Df ray = new Line3Df(); ray.Start = new Vector3Df(camera.Position); ray.End = ray.Start + (camera.Target - ray.Start).Normalize() * 1000.0f; // Tracks the current intersection point with the level or a mesh Vector3Df intersection; // Used to show with triangle has been hit Triangle3Df hitTriangle; // This call is all you need to perform ray/triangle collision on every scene node // that has a triangle selector, including the Quake level mesh. It finds the nearest // collision point/triangle, and returns the scene node containing that point. // Irrlicht provides other types of selection, including ray/triangle selector, // ray/box and ellipse/triangle selector, plus associated helpers. // See the methods of ISceneCollisionManager SceneNode selectedSceneNode = collMan.GetSceneNodeAndCollisionPointFromRay( ray, out intersection, // This will be the position of the collision out hitTriangle, // This will be the triangle hit in the collision IDFlag_IsPickable); // This ensures that only nodes that we have set up to be pickable are considered // If the ray hit anything, move the billboard to the collision position // and draw the triangle that was hit. if (selectedSceneNode != null) { bill.Position = new Vector3Df(intersection); // We need to reset the transform before doing our own rendering. driver.SetTransform(TransformationState.World, Matrix.Identity); driver.SetMaterial(material); driver.Draw3DTriangle(hitTriangle, new Color(255, 0, 0)); // We can check the flags for the scene node that was hit to see if it should be // highlighted. The animated nodes can be highlighted, but not the Quake level mesh if ((selectedSceneNode.ID & IDFlag_IsHighlightable) == IDFlag_IsHighlightable) { highlightedSceneNode = selectedSceneNode; // Highlighting in this case means turning lighting OFF for this node, // which means that it will be drawn with full brightness. highlightedSceneNode.SetMaterialFlag(MaterialFlag.Lighting, false); } } // We're all done drawing, so end the scene. driver.EndScene(); int fps = driver.FPS; if (lastFPS != fps) { device.SetWindowCaption(String.Format( "Collision detection example - Irrlicht Engine [{0}] fps: {1}", driver.Name, fps)); lastFPS = fps; } } device.Drop(); }
/// <summary> /// The irrlicht thread for rendering. /// </summary> private void StartIrr() { try { //Setup IrrlichtCreationParameters irrparam = new IrrlichtCreationParameters(); if (irrlichtPanel.IsDisposed) { throw new Exception("Form closed!"); } if (irrlichtPanel.InvokeRequired) { irrlichtPanel.Invoke(new MethodInvoker(delegate { irrparam.WindowID = irrlichtPanel.Handle; })); } irrparam.DriverType = DriverType.Direct3D9; irrparam.DriverType = DriverType.OpenGL; irrparam.BitsPerPixel = 16; device = IrrlichtDevice.CreateDevice(irrparam); if (device == null) { throw new NullReferenceException("Could not create device for engine!"); } driver = device.VideoDriver; smgr = device.SceneManager; gui = device.GUIEnvironment; var cam = smgr.AddCameraSceneNode(null); cam.TargetAndRotationBinding = true; cam.Position = new Vector3Df(-100.0f, 500.0f, 100.0f); cam.Target = new Vector3Df(0.0f); cam.FarValue = 42000.0f; device.CursorControl.Visible = false; //Terrain heightmap = driver.CreateImage("Terrain\\basemap.bmp"); terrain = smgr.AddTerrainSceneNode( "Terrain\\basemap.bmp", null, -1, new Vector3Df(0.0f) ); terrain.Scale = new Vector3Df(32, 5, 32); terrain.SetMaterialFlag(MaterialFlag.Lighting, false); terrain.SetMaterialTexture(0, driver.GetTexture("Terrain\\rockwall.jpg")); selector = smgr.CreateTerrainTriangleSelector(terrain, 0); var arrow = smgr.AddAnimatedMeshSceneNode(smgr.AddArrowMesh("arrow", new IrrlichtLime.Video.Color(255, 255, 0, 0), new IrrlichtLime.Video.Color(255, 0, 255, 0)), null); arrow.SetMaterialFlag(MaterialFlag.Lighting, false); arrow.Scale = new Vector3Df(100.0f); arrow.Rotation = new Vector3Df(0.0f, 0.0f, 180.0f); //Skybox and skydome driver.SetTextureCreationFlag(TextureCreationFlag.CreateMipMaps, false); /*var box = smgr.AddSkyBoxSceneNode( * ("Terrain\\irrlicht2_up.jpg"), * ("Terrain\\irrlicht2_dn.jpg"), * ("Terrain\\irrlicht2_lf.jpg"), * ("Terrain\\irrlicht2_rt.jpg"), * ("Terrain\\irrlicht2_ft.jpg"), * ("Terrain\\irrlicht2_bk.jpg")); * box.Visible = true;*/ var dome = smgr.AddSkyDomeSceneNode(driver.GetTexture("Terrain\\skydome.jpg"), 16, 8, 0.95f, 2.0f); dome.Visible = true; driver.SetTextureCreationFlag(TextureCreationFlag.CreateMipMaps, true); var helpq = gui.AddStaticText("Press Q to disable focus!", new Recti(0, this.ClientSize.Height - 40, 100, this.ClientSize.Height), true, true, null, 1, true); var helpesc = gui.AddStaticText("Press ESC to quit", new Recti(0, this.ClientSize.Height - 20, 100, this.ClientSize.Height), true, true, null, 1, true); middletext = gui.AddStaticText("Click to enable mouselook and move with WASD", new Recti(ClientSize.Width / 2 - 100, this.ClientSize.Height / 2, ClientSize.Width / 2 + 100, this.ClientSize.Height / 2 + 30), true, true, null, 1, true); middletext.OverrideColor = IrrlichtLime.Video.Color.SolidWhite; middletext.BackgroundColor = IrrlichtLime.Video.Color.SolidBlack; var irrTimer = device.Timer; var then = 0; var then30 = 0; device.CursorControl.Visible = false; Vector2Df lastcurr = new Vector2Df(0f); uint dt = 0; while (device.Run()) { driver.BeginScene(ClearBufferFlag.All); if (catchmouse) { // move the arrow to the nearest vertex ... IrrlichtLime.Core.Vector2Di center = new IrrlichtLime.Core.Vector2Di(irrlichtPanel.Width / 2, irrlichtPanel.Height / 2); Line3Df ray = smgr.SceneCollisionManager.GetRayFromScreenCoordinates(center, cam); Vector3Df pos; Triangle3Df Tri; var curr = device.CursorControl.RelativePosition; // Threshold and periodical check so we don't spin around due to float conversions if (device.Timer.Time > dt && curr.GetDistanceFrom(lastcurr) > 0.01f) { Line3Df cursor_ray = smgr.SceneCollisionManager .GetRayFromScreenCoordinates(new Vector2Di((int)(curr.X * irrlichtPanel.Width), (int)(curr.Y * irrlichtPanel.Height)), cam); smgr.ActiveCamera.Target = cursor_ray.Middle; dt = device.Timer.Time + 30; lastcurr = curr; device.CursorControl.Position = center; } if (smgr.SceneCollisionManager.GetCollisionPoint(ray, selector, out pos, out Tri, out outnode)) { var scale = 32; // terrain is scaled 32X var size = 512; // heightmap is 512x512 pixels var x = (pos.X / scale); var z = (pos.Z / scale); var index = x * size + z; x *= scale; z *= scale; arrow.Position = new Vector3Df(x, terrain.GetHeight(x, z) + 100, z); } } smgr.DrawAll(); gui.DrawAll(); driver.EndScene(); //device.CursorControl.Position = new Vector2Di(irrlichtPanel. } device.Drop(); } catch (ThreadAbortException) { } catch (NullReferenceException) { } catch (Exception ex) { if (!this.IsDisposed) { MessageBox.Show(ex.Message); //this.Invoke(new MethodInvoker(delegate { this.Close(); })); } } }