/// <summary> /// Aktualisiert den Spieler (Bewegung, Interaktion) /// </summary> /// <param name="frameTime">Die aktuelle Zeit.</param> public void Update(GameTime frameTime) { #region Inputverarbeitung // Input verarbeiten Player.Angle += (float)frameTime.ElapsedGameTime.TotalSeconds * Head.X; Player.Tilt += (float)frameTime.ElapsedGameTime.TotalSeconds * Head.Y; Player.Tilt = Math.Min(1.5f, Math.Max(-1.5f, Player.Tilt)); #endregion #region Physik float lookX = (float)Math.Cos(Player.Angle); float lookY = -(float)Math.Sin(Player.Angle); var velocitydirection = new Vector3(lookX, lookY, 0) * Move.Y; float stafeX = (float)Math.Cos(Player.Angle + MathHelper.PiOver2); float stafeY = -(float)Math.Sin(Player.Angle + MathHelper.PiOver2); velocitydirection += new Vector3(stafeX, stafeY, 0) * Move.X; Player.Velocity += PhysicalUpdate(velocitydirection, frameTime.ElapsedGameTime, !Player.FlyMode, Player.FlyMode); #endregion #region Playerbewegung Vector3 move = Player.Velocity * (float)frameTime.ElapsedGameTime.TotalSeconds; Player.OnGround = false; bool collision = false; int loop = 0; do { int minx = (int)Math.Floor(Math.Min( Player.Position.BlockPosition.X - Player.Radius, Player.Position.BlockPosition.X - Player.Radius + move.X)); int maxx = (int)Math.Floor(Math.Max( Player.Position.BlockPosition.X + Player.Radius, Player.Position.BlockPosition.X + Player.Radius + move.X)); int miny = (int)Math.Floor(Math.Min( Player.Position.BlockPosition.Y - Player.Radius, Player.Position.BlockPosition.Y - Player.Radius + move.Y)); int maxy = (int)Math.Floor(Math.Max( Player.Position.BlockPosition.Y + Player.Radius, Player.Position.BlockPosition.Y + Player.Radius + move.Y)); int minz = (int)Math.Floor(Math.Min( Player.Position.BlockPosition.Z, Player.Position.BlockPosition.Z + move.Z)); int maxz = (int)Math.Floor(Math.Max( Player.Position.BlockPosition.Z + Player.Height, Player.Position.BlockPosition.Z + Player.Height + move.Z)); // Relative PlayerBox BoundingBox playerBox = new BoundingBox( new Vector3( Player.Position.BlockPosition.X - Player.Radius, Player.Position.BlockPosition.Y - Player.Radius, Player.Position.BlockPosition.Z), new Vector3( Player.Position.BlockPosition.X + Player.Radius, Player.Position.BlockPosition.Y + Player.Radius, Player.Position.BlockPosition.Z + Player.Height)); collision = false; float min = 1f; Axis minAxis = Axis.None; for (int z = minz; z <= maxz; z++) { for (int y = miny; y <= maxy; y++) { for (int x = minx; x <= maxx; x++) { Index3 pos = new Index3(x, y, z); Index3 blockPos = pos + Player.Position.GlobalBlockIndex; ushort block = localChunkCache.GetBlock(blockPos); if (block == 0) { continue; } Axis? localAxis; IBlockDefinition blockDefinition = DefinitionManager.Instance.GetBlockDefinitionByIndex(block); float? moveFactor = Block.Intersect( blockDefinition.GetCollisionBoxes(localChunkCache, blockPos.X, blockPos.Y, blockPos.Z), pos, playerBox, move, out localAxis); if (moveFactor.HasValue && moveFactor.Value < min) { collision = true; min = moveFactor.Value; minAxis = localAxis.Value; } } } } Player.Position += (move * min); move *= (1f - min); switch (minAxis) { case Axis.X: Player.Velocity *= new Vector3(0, 1, 1); Player.Position += new Vector3(move.X > 0 ? -Gap : Gap, 0, 0); move.X = 0f; break; case Axis.Y: Player.Velocity *= new Vector3(1, 0, 1); Player.Position += new Vector3(0, move.Y > 0 ? -Gap : Gap, 0); move.Y = 0f; break; case Axis.Z: Player.OnGround = true; Player.Velocity *= new Vector3(1, 1, 0); Player.Position += new Vector3(0, 0, move.Z > 0 ? -Gap : Gap); move.Z = 0f; break; } // Koordinate normalisieren (Rundwelt) Coordinate position = Player.Position; position.NormalizeChunkIndexXY(planet.Size); //Beam me up KeyboardState ks = Keyboard.GetState(); if (ks.IsKeyDown(Keys.P)) { position = position + new Vector3(0, 0, 10); } Player.Position = position; loop++; }while (collision && loop < 3); if (Player.Position.ChunkIndex != _oldIndex) { _oldIndex = Player.Position.ChunkIndex; ReadyState = false; localChunkCache.SetCenter(planet, new Index2(Player.Position.ChunkIndex), (success) => { ReadyState = success; }); } #endregion #region Block Interaction if (lastInteract.HasValue) { ushort lastBlock = localChunkCache.GetBlock(lastInteract.Value); localChunkCache.SetBlock(lastInteract.Value, 0); if (lastBlock != 0) { var blockDefinition = DefinitionManager.Instance.GetBlockDefinitionByIndex(lastBlock); var slot = Player.Inventory.Where(s => s.Definition == blockDefinition && s.Amount < blockDefinition.StackLimit).FirstOrDefault(); // Wenn noch kein Slot da ist oder der vorhandene voll, dann neuen Slot if (slot == null || slot.Amount >= blockDefinition.StackLimit) { slot = new InventorySlot() { Definition = blockDefinition, Amount = 0 }; Player.Inventory.Add(slot); } slot.Amount++; } lastInteract = null; } if (lastApply.HasValue) { if (ActiveTool != null) { Index3 add = new Index3(); switch (lastOrientation) { case OrientationFlags.SideWest: add = new Index3(-1, 0, 0); break; case OrientationFlags.SideEast: add = new Index3(1, 0, 0); break; case OrientationFlags.SideSouth: add = new Index3(0, -1, 0); break; case OrientationFlags.SideNorth: add = new Index3(0, 1, 0); break; case OrientationFlags.SideBottom: add = new Index3(0, 0, -1); break; case OrientationFlags.SideTop: add = new Index3(0, 0, 1); break; } if (ActiveTool.Definition is IBlockDefinition) { IBlockDefinition definition = ActiveTool.Definition as IBlockDefinition; localChunkCache.SetBlock(lastApply.Value + add, DefinitionManager.Instance.GetBlockDefinitionIndex(definition)); ActiveTool.Amount--; if (ActiveTool.Amount <= 0) { Player.Inventory.Remove(ActiveTool); ActiveTool = null; } } // TODO: Fix Interaction ;) //ushort block = _manager.GetBlock(lastApply.Value); //IBlockDefinition blockDefinition = BlockDefinitionManager.GetForType(block); //IItemDefinition itemDefinition = ActiveTool.Definition; //blockDefinition.Hit(blockDefinition, itemDefinition.GetProperties(null)); //itemDefinition.Hit(null, blockDefinition.GetProperties(block)); } lastApply = null; } #endregion }
/// <summary> /// Aktualisiert den Spieler (Bewegung, Interaktion) /// </summary> /// <param name="frameTime">Die aktuelle Zeit.</param> public void Update(GameTime frameTime) { #region Inputverarbeitung // Input verarbeiten Player.Angle += (float)frameTime.ElapsedGameTime.TotalSeconds * Head.X; Player.Tilt += (float)frameTime.ElapsedGameTime.TotalSeconds * Head.Y; Player.Tilt = Math.Min(1.5f, Math.Max(-1.5f, Player.Tilt)); #endregion #region Physik float lookX = (float)Math.Cos(Player.Angle); float lookY = -(float)Math.Sin(Player.Angle); var velocitydirection = new Vector3(lookX, lookY, 0) * Move.Y; float stafeX = (float)Math.Cos(Player.Angle + MathHelper.PiOver2); float stafeY = -(float)Math.Sin(Player.Angle + MathHelper.PiOver2); velocitydirection += new Vector3(stafeX, stafeY, 0) * Move.X; Player.Velocity += PhysicalUpdate(velocitydirection, frameTime.ElapsedGameTime, !Player.FlyMode, Player.FlyMode); #endregion #region Playerbewegung /Kollision Vector3 move = Player.Velocity * (float)frameTime.ElapsedGameTime.TotalSeconds; Player.OnGround = false; //Blocks finden die eine Kollision verursachen könnten int minx = (int)Math.Floor(Math.Min( Player.Position.BlockPosition.X - Player.Radius, Player.Position.BlockPosition.X - Player.Radius + move.X)); int maxx = (int)Math.Ceiling(Math.Max( Player.Position.BlockPosition.X + Player.Radius, Player.Position.BlockPosition.X + Player.Radius + move.X)); int miny = (int)Math.Floor(Math.Min( Player.Position.BlockPosition.Y - Player.Radius, Player.Position.BlockPosition.Y - Player.Radius + move.Y)); int maxy = (int)Math.Ceiling(Math.Max( Player.Position.BlockPosition.Y + Player.Radius, Player.Position.BlockPosition.Y + Player.Radius + move.Y)); int minz = (int)Math.Floor(Math.Min( Player.Position.BlockPosition.Z, Player.Position.BlockPosition.Z + move.Z)); int maxz = (int)Math.Ceiling(Math.Max( Player.Position.BlockPosition.Z + Player.Height, Player.Position.BlockPosition.Z + Player.Height + move.Z)); //Beteiligte Flächen des Spielers var playerplanes = CollisionPlane.GetPlayerCollisionPlanes(Player).ToList(); bool abort = false; for (int z = minz; z <= maxz && !abort; z++) { for (int y = miny; y <= maxy && !abort; y++) { for (int x = minx; x <= maxx && !abort; x++) { move = Player.Velocity * (float)frameTime.ElapsedGameTime.TotalSeconds; Index3 pos = new Index3(x, y, z); Index3 blockPos = pos + Player.Position.GlobalBlockIndex; ushort block = localChunkCache.GetBlock(blockPos); if (block == 0) { continue; } var blockplane = CollisionPlane.GetBlockCollisionPlanes(pos, Player.Velocity).ToList(); var planes = from pp in playerplanes from bp in blockplane where CollisionPlane.Intersect(bp, pp) let distance = CollisionPlane.GetDistance(bp, pp) where CollisionPlane.CheckDistance(distance, move) select new { BlockPlane = bp, PlayerPlane = pp, Distance = distance }; foreach (var plane in planes) { var subvelocity = (plane.Distance / (float)frameTime.ElapsedGameTime.TotalSeconds); var diff = Player.Velocity - subvelocity; float vx; float vy; float vz; if (plane.BlockPlane.normal.X != 0 && (Player.Velocity.X > 0 && diff.X >= 0 && subvelocity.X >= 0 || Player.Velocity.X < 0 && diff.X <= 0 && subvelocity.X <= 0)) { vx = subvelocity.X; } else { vx = Player.Velocity.X; } if (plane.BlockPlane.normal.Y != 0 && (Player.Velocity.Y > 0 && diff.Y >= 0 && subvelocity.Y >= 0 || Player.Velocity.Y < 0 && diff.Y <= 0 && subvelocity.Y <= 0)) { vy = subvelocity.Y; } else { vy = Player.Velocity.Y; } if (plane.BlockPlane.normal.Z != 0 && (Player.Velocity.Z > 0 && diff.Z >= 0 && subvelocity.Z >= 0 || Player.Velocity.Z < 0 && diff.Z <= 0 && subvelocity.Z <= 0)) { vz = subvelocity.Z; } else { vz = Player.Velocity.Z; } Player.Velocity = new Vector3(vx, vy, vz); if (vx == 0 && vy == 0 && vz == 0) { abort = true; break; } } } } } // TODO: Was ist für den Fall Gravitation = 0 oder im Scheitelpunkt des Sprungs? Player.OnGround = Player.Velocity.Z == 0f; Coordinate position = Player.Position + Player.Velocity * (float)frameTime.ElapsedGameTime.TotalSeconds; position.NormalizeChunkIndexXY(planet.Size); Player.Position = position; //Beam me up KeyboardState ks = Keyboard.GetState(); if (ks.IsKeyDown(Keys.P)) { Player.Position += new Vector3(0, 0, 10); } if (Player.Position.ChunkIndex != _oldIndex) { _oldIndex = Player.Position.ChunkIndex; ReadyState = false; localChunkCache.SetCenter(planet, new Index2(Player.Position.ChunkIndex), (success) => { ReadyState = success; }); } #endregion #region Block Interaction if (lastInteract.HasValue) { ushort lastBlock = localChunkCache.GetBlock(lastInteract.Value); localChunkCache.SetBlock(lastInteract.Value, 0); if (lastBlock != 0) { var blockDefinition = DefinitionManager.Instance.GetBlockDefinitionByIndex(lastBlock); var slot = Player.Inventory.FirstOrDefault(s => s.Definition == blockDefinition); // Wenn noch kein Slot da ist oder der vorhandene voll, dann neuen Slot if (slot == null) { slot = new InventorySlot() { Definition = blockDefinition, Amount = 0 }; Player.Inventory.Add(slot); for (int i = 0; i < Player.Tools.Length; i++) { if (Player.Tools[i] == null) { Player.Tools[i] = slot; break; } } } slot.Amount += 125; } lastInteract = null; } if (lastApply.HasValue) { if (ActiveTool != null) { Index3 add = new Index3(); switch (lastOrientation) { case OrientationFlags.SideWest: add = new Index3(-1, 0, 0); break; case OrientationFlags.SideEast: add = new Index3(1, 0, 0); break; case OrientationFlags.SideSouth: add = new Index3(0, -1, 0); break; case OrientationFlags.SideNorth: add = new Index3(0, 1, 0); break; case OrientationFlags.SideBottom: add = new Index3(0, 0, -1); break; case OrientationFlags.SideTop: add = new Index3(0, 0, 1); break; } if (ActiveTool.Definition is IBlockDefinition) { IBlockDefinition definition = ActiveTool.Definition as IBlockDefinition; Index3 idx = lastApply.Value + add; var boxes = definition.GetCollisionBoxes(localChunkCache, idx.X, idx.Y, idx.Z); float gap = 0.01f; var playerBox = new BoundingBox( new Vector3( Player.Position.GlobalBlockIndex.X + Player.Position.BlockPosition.X - Player.Radius + gap, Player.Position.GlobalBlockIndex.Y + Player.Position.BlockPosition.Y - Player.Radius + gap, Player.Position.GlobalBlockIndex.Z + Player.Position.BlockPosition.Z + gap), new Vector3( Player.Position.GlobalBlockIndex.X + Player.Position.BlockPosition.X + Player.Radius - gap, Player.Position.GlobalBlockIndex.Y + Player.Position.BlockPosition.Y + Player.Radius - gap, Player.Position.GlobalBlockIndex.Z + Player.Position.BlockPosition.Z + Player.Height - gap) ); // Nicht in sich selbst reinbauen bool intersects = false; foreach (var box in boxes) { var newBox = new BoundingBox(idx + box.Min, idx + box.Max); if (newBox.Min.X < playerBox.Max.X && newBox.Max.X > playerBox.Min.X && newBox.Min.Y < playerBox.Max.Y && newBox.Max.X > playerBox.Min.Y && newBox.Min.Z < playerBox.Max.Z && newBox.Max.X > playerBox.Min.Z) { intersects = true; } } if (!intersects) { localChunkCache.SetBlock(idx, DefinitionManager.Instance.GetBlockDefinitionIndex(definition)); ActiveTool.Amount -= 125; if (ActiveTool.Amount <= 0) { Player.Inventory.Remove(ActiveTool); for (int i = 0; i < Player.Tools.Length; i++) { if (Player.Tools[i] == ActiveTool) { Player.Tools[i] = null; } } ActiveTool = null; } } } // TODO: Fix Interaction ;) //ushort block = _manager.GetBlock(lastApply.Value); //IBlockDefinition blockDefinition = BlockDefinitionManager.GetForType(block); //IItemDefinition itemDefinition = ActiveTool.Definition; //blockDefinition.Hit(blockDefinition, itemDefinition.GetProperties(null)); //itemDefinition.Hit(null, blockDefinition.GetProperties(block)); } lastApply = null; } #endregion }