public LineIntersection ( IsBlockEmpty isEmpty, GetBlockHeight getBlockHeight, |
||
isEmpty | IsBlockEmpty | |
getBlockHeight | GetBlockHeight | |
line | ||
return | IEnumerable |
private void UpdatePicking() { bool left = Mouse[OpenTK.Input.MouseButton.Left];//destruct bool middle = Mouse[OpenTK.Input.MouseButton.Middle];//clone material as active bool right = Mouse[OpenTK.Input.MouseButton.Right];//build if (!leftpressedpicking) { if (mouseleftclick) { leftpressedpicking = true; } else { left = false; } } else { if (mouseleftdeclick) { leftpressedpicking = false; left = false; } } if (!left) { currentAttackedBlock = null; } float pick_distance = PICK_DISTANCE; if (cameratype == CameraType.Tpp) { pick_distance = tppcameradistance * 2; } if (cameratype == CameraType.Overhead) { pick_distance = overheadcameradistance; } float unit_x = 0; float unit_y = 0; int NEAR = 1; int FOV = 600; float ASPECT = 640f / 480; float near_height = NEAR * (float)(Math.Tan(FOV * Math.PI / 360.0)); Vector3 ray = new Vector3(unit_x * near_height * ASPECT, unit_y * near_height, 1);//, 0); Vector3 ray_start_point = new Vector3(0, 0, 0); if (overheadcamera) { float mx = (float)mouse_current.X / Width - 0.5f; float my = (float)mouse_current.Y / Height - 0.5f; //ray_start_point = new Vector3(mx * 1.4f, -my * 1.1f, 0.0f); ray_start_point = new Vector3(mx * 3f, -my * 2.2f, -1.0f); } //Matrix4 the_modelview; //Read the current modelview matrix into the array the_modelview //GL.GetFloat(GetPName.ModelviewMatrix, out the_modelview); if (d_The3d.ModelViewMatrix.Equals(new Matrix4())) { return; } Matrix4 theModelView = d_The3d.ModelViewMatrix; theModelView.Invert(); //the_modelview = new Matrix4(); ray = Vector3.Transform(ray, theModelView); ray_start_point = Vector3.Transform(ray_start_point, theModelView); Line3D pick = new Line3D(); Vector3 raydir = -(ray - ray_start_point); raydir.Normalize(); pick.Start = ray + Vector3.Multiply(raydir, 1f); //do not pick behind pick.End = ray + Vector3.Multiply(raydir, pick_distance * 2); //pick models selectedmodelid = -1; foreach (var m in Models) { Vector3 closestmodelpos = new Vector3(int.MaxValue, int.MaxValue, int.MaxValue); foreach (var t in m.TrianglesForPicking) { Vector3 intersection; if (Collisions.Intersection.RayTriangle(pick, t, out intersection) == 1) { if ((pick.Start - intersection).Length > pick_distance) { continue; } if ((pick.Start - intersection).Length < (pick.Start - closestmodelpos).Length) { closestmodelpos = intersection; selectedmodelid = m.Id; } } } } if (selectedmodelid != -1) { pickcubepos = new Vector3(-1, -1, -1); if (mouseleftclick) { ModelClick(selectedmodelid); } mouseleftclick = false; leftpressedpicking = false; return; } if (left) { d_Weapon.SetAttack(true, false); } else if (right) { d_Weapon.SetAttack(true, true); } //if (iii++ % 2 == 0) { //To improve speed, update picking only every second frame. //return; } //pick terrain var s = new BlockOctreeSearcher(); s.StartBox = new Box3D(0, 0, 0, BitTools.NextPowerOfTwo((uint)Math.Max(d_Map.MapSizeX, Math.Max(d_Map.MapSizeY, d_Map.MapSizeZ)))); List<BlockPosSide> pick2 = new List<BlockPosSide>(s.LineIntersection(IsTileEmptyForPhysics, getblockheight, pick)); pick2.Sort((a, b) => { return (a.pos - ray_start_point).Length.CompareTo((b.pos - ray_start_point).Length); }); if (overheadcamera && pick2.Count > 0 && left) { //if not picked any object, and mouse button is pressed, then walk to destination. playerdestination = pick2[0].pos; } bool pickdistanceok = pick2.Count > 0 && (pick2[0].pos - (player.playerposition)).Length <= pick_distance; bool playertileempty = IsTileEmptyForPhysics( (int)ToMapPos(player.playerposition).X, (int)ToMapPos(player.playerposition).Y, (int)ToMapPos(player.playerposition).Z); bool playertileemptyclose = IsTileEmptyForPhysicsClose( (int)ToMapPos(player.playerposition).X, (int)ToMapPos(player.playerposition).Y, (int)ToMapPos(player.playerposition).Z); BlockPosSide pick0; if (pick2.Count > 0 && ((pickdistanceok && (playertileempty || (playertileemptyclose))) || overheadcamera) ) { pickcubepos = pick2[0].Current(); pickcubepos = new Vector3((int)pickcubepos.X, (int)pickcubepos.Y, (int)pickcubepos.Z); pick0 = pick2[0]; } else { pickcubepos = new Vector3(-1, -1, -1); pick0.pos = new Vector3(-1, -1, -1); pick0.side = TileSide.Front; } if (FreeMouse) { if (pick2.Count > 0) { OnPick(pick0); } return; } var ntile = pick0.Current(); if(IsUsableBlock(d_Map.GetBlock((int)ntile.X, (int)ntile.Z, (int)ntile.Y))) { currentAttackedBlock = new Vector3i((int)ntile.X, (int)ntile.Z, (int)ntile.Y); } if ((DateTime.Now - lastbuild).TotalSeconds >= BuildDelay) { if (left && d_Inventory.RightHand[ActiveMaterial] == null) { PacketClientHealth p = new PacketClientHealth { CurrentHealth = (int)(2 + rnd.NextDouble() * 4) }; SendPacket(Serialize(new PacketClient() { PacketId = ClientPacketId.MonsterHit, Health = p })); } if (left && !fastclicking) { //todo animation fastclicking = false; } if (left || right || middle) { lastbuild = DateTime.Now; } if (pick2.Count > 0) { if (middle) { var newtile = pick0.Current(); if (MapUtil.IsValidPos(d_Map, (int)newtile.X, (int)newtile.Z, (int)newtile.Y)) { int clonesource = d_Map.GetBlock((int)newtile.X, (int)newtile.Z, (int)newtile.Y); int clonesource2 = (int)d_Data.WhenPlayerPlacesGetsConvertedTo[(int)clonesource]; //find this block in another right hand. for (int i = 0; i < 10; i++) { if (d_Inventory.RightHand[i] != null && d_Inventory.RightHand[i].ItemClass == ItemClass.Block && (int)d_Inventory.RightHand[i].BlockId == clonesource2) { ActiveMaterial = i; goto done; } } int? freehand = d_InventoryUtil.FreeHand(ActiveMaterial); //find this block in inventory. foreach (var k in d_Inventory.Items) { if (k.Value.ItemClass == ItemClass.Block && k.Value.BlockId == clonesource2) { //free hand if (freehand != null) { d_InventoryController.WearItem( InventoryPosition.MainArea(k.Key.ToPoint()), InventoryPosition.MaterialSelector(freehand.Value)); goto done; } //try to replace current slot if (d_Inventory.RightHand[ActiveMaterial] != null && d_Inventory.RightHand[ActiveMaterial].ItemClass == ItemClass.Block) { d_InventoryController.MoveToInventory( InventoryPosition.MaterialSelector(ActiveMaterial)); d_InventoryController.WearItem( InventoryPosition.MainArea(k.Key.ToPoint()), InventoryPosition.MaterialSelector(ActiveMaterial)); } } } done: d_Audio.Play(d_Data.CloneSound[clonesource][0]); //todo sound cycle } } if (left || right) { BlockPosSide tile = pick0; Console.Write(tile.pos + ":" + Enum.GetName(typeof(TileSide), tile.side)); Vector3 newtile = right ? tile.Translated() : tile.Current(); if (MapUtil.IsValidPos(d_Map, (int)newtile.X, (int)newtile.Z, (int)newtile.Y)) { Console.WriteLine(". newtile:" + newtile + " type: " + d_Map.GetBlock((int)newtile.X, (int)newtile.Z, (int)newtile.Y)); if (pick0.pos != new Vector3(-1, -1, -1)) { int blocktype; if (left) { blocktype = d_Map.GetBlock((int)newtile.X, (int)newtile.Z, (int)newtile.Y); } else { blocktype = materialSlots[ActiveMaterial]; } if (left && blocktype == d_Data.BlockIdAdminium) { goto end; } string[] sound = left ? d_Data.BreakSound[blocktype] : d_Data.BuildSound[blocktype]; if (sound != null && sound.Length > 0) { d_Audio.Play(sound[0]); //todo sound cycle } } //normal attack if (!right) { //attack var pos = new Vector3i((int)newtile.X, (int)newtile.Z, (int)newtile.Y); currentAttackedBlock = new Vector3i(pos.x,pos.y,pos.z); if (!blockhealth.ContainsKey(pos)) { blockhealth[pos] = GetCurrentBlockHealth(pos.x, pos.y, pos.z); } blockhealth[pos] -= WeaponAttackStrength(); float health = GetCurrentBlockHealth(pos.x,pos.y,pos.z); if (health <= 0) { if (currentAttackedBlock != null) { blockhealth.Remove(currentAttackedBlock.Value); } currentAttackedBlock = null; goto broken; } goto end; } if (!right) { particleEffectBlockBreak.StartParticleEffect(newtile);//must be before deletion - gets ground type. } if (!MapUtil.IsValidPos(d_Map, (int)newtile.X, (int)newtile.Z, (int)newtile.Y)) { throw new Exception(); } broken: OnPick(new Vector3((int)newtile.X, (int)newtile.Z, (int)newtile.Y), new Vector3((int)tile.Current().X, (int)tile.Current().Z, (int)tile.Current().Y), tile.pos, right); //network.SendSetBlock(new Vector3((int)newtile.X, (int)newtile.Z, (int)newtile.Y), // right ? BlockSetMode.Create : BlockSetMode.Destroy, (byte)MaterialSlots[activematerial]); } } } } end: fastclicking = false; if (!(left || right || middle)) { lastbuild = new DateTime(); fastclicking = true; } }
private void UpdatePicking() { bool left = Mouse[OpenTK.Input.MouseButton.Left];//destruct bool middle = Mouse[OpenTK.Input.MouseButton.Middle];//clone material as active bool right = Mouse[OpenTK.Input.MouseButton.Right];//build if (!leftpressedpicking) { if (mouseleftclick) { leftpressedpicking = true; } else { left = false; } } else { if (mouseleftdeclick) { leftpressedpicking = false; left = false; } } float unit_x = 0; float unit_y = 0; int NEAR = 1; int FOV = 600; float ASPECT = 640f / 480; float near_height = NEAR * (float)(Math.Tan(FOV * Math.PI / 360.0)); Vector3 ray = new Vector3(unit_x * near_height * ASPECT, unit_y * near_height, 1);//, 0); Vector3 ray_start_point = new Vector3(0, 0, 0); if (overheadcamera) { float mx = (float)mouse_current.X / Width - 0.5f; float my = (float)mouse_current.Y / Height - 0.5f; //ray_start_point = new Vector3(mx * 1.4f, -my * 1.1f, 0.0f); ray_start_point = new Vector3(mx * 3f, -my * 2.2f, -1.0f); } //Matrix4 the_modelview; //Read the current modelview matrix into the array the_modelview //GL.GetFloat(GetPName.ModelviewMatrix, out the_modelview); if (m_theModelView.Equals(new Matrix4())) { return; } Matrix4 theModelView = m_theModelView; theModelView.Invert(); //the_modelview = new Matrix4(); ray = Vector3.Transform(ray, theModelView); ray_start_point = Vector3.Transform(ray_start_point, theModelView); var pick = new Line3D(); var raydir = -(ray - ray_start_point); raydir.Normalize(); raydir = Vector3.Multiply(raydir, 100); pick.Start = ray + Vector3.Multiply(raydir, 0.01f); //do not pick behind pick.End = ray + raydir; //pick models selectedmodelid = -1; foreach (var m in game.Models) { Vector3 closestmodelpos = new Vector3(int.MaxValue,int.MaxValue,int.MaxValue); foreach (var t in m.TrianglesForPicking) { Vector3 intersection; if (Collisions.Intersection.RayTriangle(pick, t, out intersection) == 1) { if ((pick.Start - intersection).Length > PICK_DISTANCE) { continue; } if ((pick.Start - intersection).Length < (pick.Start - closestmodelpos).Length) { closestmodelpos = intersection; selectedmodelid = m.Id; } } } } if (selectedmodelid != -1) { pickcubepos = new Vector3(-1, -1, -1); if (mouseleftclick) { game.ModelClick(selectedmodelid); } mouseleftclick = false; leftpressedpicking = false; return; } if (left) { weapon.SetAttack(true, false); } else if (right) { weapon.SetAttack(true, true); } if (iii++ % 2 == 0) { return; } //pick terrain var s = new BlockOctreeSearcher(); s.StartBox = new Box3D(0, 0, 0, NextPowerOfTwo((uint)Math.Max(map.MapSizeX, Math.Max(map.MapSizeY, map.MapSizeZ)))); List<BlockPosSide> pick2 = new List<BlockPosSide>(s.LineIntersection(IsTileEmptyForPhysics, getblockheight, pick)); pick2.Sort((a, b) => { return (a.pos - ray_start_point).Length.CompareTo((b.pos - ray_start_point).Length); }); if (overheadcamera && pick2.Count > 0 && left) { //if not picked any object, and mouse button is pressed, then walk to destination. playerdestination = pick2[0].pos; } bool pickdistanceok = pick2.Count > 0 && (pick2[0].pos - (player.playerposition)).Length <= PICK_DISTANCE; bool playertileempty = IsTileEmptyForPhysics( (int)ToMapPos(player.playerposition).X, (int)ToMapPos(player.playerposition).Y, (int)ToMapPos(player.playerposition).Z); bool playertileemptyclose = IsTileEmptyForPhysicsClose( (int)ToMapPos(player.playerposition).X, (int)ToMapPos(player.playerposition).Y, (int)ToMapPos(player.playerposition).Z); BlockPosSide pick0; if (pick2.Count > 0 && ((pickdistanceok && (playertileempty || (playertileemptyclose)) ) || overheadcamera) ) { pickcubepos = pick2[0].Current(); pickcubepos = new Vector3((int)pickcubepos.X, (int)pickcubepos.Y, (int)pickcubepos.Z); pick0 = pick2[0]; } else { pickcubepos = new Vector3(-1, -1, -1); pick0.pos = new Vector3(-1, -1, -1); pick0.side = TileSide.Front; } if (FreeMouse) { if (pick2.Count > 0) { OnPick(pick0); } return; } if ((DateTime.Now - lastbuild).TotalSeconds >= BuildDelay) { if (left && !fastclicking) { //todo animation fastclicking = false; } if (left || right || middle) { lastbuild = DateTime.Now; } if (pick2.Count > 0) { if (middle) { var newtile = pick0.Current(); if (MapUtil.IsValidPos(map, (int)newtile.X, (int)newtile.Z, (int)newtile.Y)) { int clonesource = map.GetBlock((int)newtile.X, (int)newtile.Z, (int)newtile.Y); clonesource = (int)data.PlayerBuildableMaterialType((int)clonesource); for (int i = 0; i < materialSlots.Length; i++) { if ((int)materialSlots[i] == clonesource) { activematerial = i; goto done; } } materialSlots[activematerial] = clonesource; done: audio.Play(soundclone); } } if (left || right) { BlockPosSide tile = pick0; Console.Write(tile.pos + ":" + Enum.GetName(typeof(TileSide), tile.side)); Vector3 newtile = right ? tile.Translated() : tile.Current(); if (MapUtil.IsValidPos(map, (int)newtile.X, (int)newtile.Z, (int)newtile.Y)) { Console.WriteLine(". newtile:" + newtile + " type: " + map.GetBlock((int)newtile.X, (int)newtile.Z, (int)newtile.Y)); if (pick0.pos != new Vector3(-1, -1, -1)) { audio.Play(left ? sounddestruct : soundbuild); } if (!right) { particleEffectBlockBreak.StartParticleEffect(newtile);//must be before deletion - gets ground type. } if (!MapUtil.IsValidPos(map, (int)newtile.X, (int)newtile.Z, (int)newtile.Y)) { throw new Exception(); } game.OnPick(new Vector3((int)newtile.X, (int)newtile.Z, (int)newtile.Y), new Vector3((int)tile.Current().X, (int)tile.Current().Z, (int)tile.Current().Y), tile.pos, right); //network.SendSetBlock(new Vector3((int)newtile.X, (int)newtile.Z, (int)newtile.Y), // right ? BlockSetMode.Create : BlockSetMode.Destroy, (byte)MaterialSlots[activematerial]); } } } } fastclicking = false; if (!(left || right || middle)) { lastbuild = new DateTime(); fastclicking = true; } }
//Don't allow to look through walls. private void LimitThirdPersonCameraToWalls(ref Vector3 eye, Vector3 target, ref float curtppcameradistance) { var ray_start_point = target; var raytarget = eye; var pick = new Line3D(); var raydir = (raytarget - ray_start_point); raydir.Normalize(); raydir = Vector3.Multiply(raydir, tppcameradistance + 1); pick.Start = ray_start_point; pick.End = ray_start_point + raydir; //pick terrain var s = new BlockOctreeSearcher(); s.StartBox = new Box3D(0, 0, 0, BitTools.NextPowerOfTwo((uint)Math.Max(d_Map.MapSizeX, Math.Max(d_Map.MapSizeY, d_Map.MapSizeZ)))); List<BlockPosSide> pick2 = new List<BlockPosSide>(s.LineIntersection(IsTileEmptyForPhysics, getblockheight, pick)); pick2.Sort((a, b) => { return (a.pos - ray_start_point).Length.CompareTo((b.pos - ray_start_point).Length); }); if (pick2.Count > 0) { var pickdistance = (pick2[0].pos - target).Length; curtppcameradistance = Math.Min(pickdistance - 1, curtppcameradistance); if (curtppcameradistance < 0.3f) { curtppcameradistance = 0.3f; } } Vector3 cameraDirection = target - eye; raydir.Normalize(); eye = target + Vector3.Multiply(raydir, curtppcameradistance); }