public void Update(Area area, GameTime gameTime) { OnUpdate(area, gameTime); // Bewegung if (destination.HasValue) { Vector2 expectedDistance = destination.Value - startPoint.Value; Vector2 currentDistance = Host.Position - startPoint.Value; // Prüfen ob das Ziel erreicht (oder überschritten) wurde. if (currentDistance.LengthSquared() > expectedDistance.LengthSquared()) { startPoint = null; destination = null; Host.Velocity = Vector2.Zero; } else { // Kurs festlegen Vector2 direction = destination.Value - Host.Position; direction.Normalize(); Host.Velocity = direction * speed * Host.MaxSpeed; } } }
/// <summary> /// Lädt alle Areas die sich aktuell im Maps-Verzeichnis befinden. /// </summary> public static Area[] LoadAll(ref int nextId) { // Alle json-Files im Map-Folder suchen string mapPath = ".\\Maps"; var files = Directory.GetFiles(mapPath, "*.json"); // Alle gefundenen json-Files laden Area[] result = new Area[files.Length]; for (int i = 0; i < files.Length; i++) result[i] = LoadFromJson(files[i], ref nextId); return result; }
public override void OnUpdate(Area area, GameTime gameTime) { // Initiales Zentrum festlegen if (!center.HasValue) center = Host.Position; if (!Walking) { // Delay abwarten if (delay > TimeSpan.Zero) { delay -= gameTime.ElapsedGameTime; return; } // Neuen Zielpunkt wählen Vector2 variation = new Vector2( (float)(Random.NextDouble() * 2 - 1.0), (float)(Random.NextDouble() * 2 - 1.0)); WalkTo(center.Value + variation * 2 * range, 0.4f); delay = TimeSpan.FromSeconds(2); } }
public override void OnUpdate(Area area, GameTime gameTime) { // Referenzpunkt ermitteln if (!startPoint.HasValue) startPoint = Host.Position; // Nach zielen ausschau halten if (target == null) { var potentialTargets = area.Items. Where(i => (i.Position - Host.Position).LengthSquared() < range * range). // Filter nach Angriffsreichweite Where(i => i.GetType() != Host.GetType()). // Items vom selben Typ verschonen OrderBy(i => (i.Position - Host.Position).LengthSquared()). // Sortiert nach Entfernung OfType<IAttackable>(). // Gefiltert nach Angreifbarkeit Where(a => a.Hitpoints > 0); // Gefiltert nach Lebendigkeit target = potentialTargets.FirstOrDefault() as Item; } // Ziel angreifen if (target != null) { attacker.AttackSignal = true; // Bei zu großem Abstand vom Ziel ablassen if ((target.Position - Host.Position).LengthSquared() > range * range || (target as IAttackable).Hitpoints <= 0) { target = null; WalkTo(startPoint.Value, 0.4f); } else { WalkTo(target.Position, 0.6f); } } }
public override void Update(GameTime gameTime) { maxVolume = game.Settings.MusicVolume * 0.05f; // Nur wenn Komponente aktiviert wurde. if (!Enabled) return; // Nur arbeiten, wenn es eine Welt, einen Player und eine aktive Area gibt. Area area = game.Local.GetCurrentArea(); if (currentArea != area) { currentArea = area; if (currentArea != null) Play(currentArea.Song); } // Override verhindern if (currentEffect == nextEffect) nextEffect = null; // Ausfaden if (currentEffect != null && nextEffect != null) { float currentVolume = currentSong.Volume; currentVolume -= (float)gameTime.ElapsedGameTime.TotalMilliseconds / totalFadeTime; if (currentVolume <= 0f) { // Ausschalten currentSong.Volume = 0; currentSong.Stop(); currentSong.Dispose(); currentSong = null; currentEffect = null; } else { // Leiser currentSong.Volume = currentVolume; } } // Einschalten if (currentEffect == null && nextEffect != null) { currentEffect = nextEffect; nextEffect = null; // Initialisieren mit 0 Lautstärke currentSong = currentEffect.CreateInstance(); currentSong.IsLooped = true; currentSong.Volume = 0f; currentSong.Play(); } // Einfaden if (currentEffect != null && nextEffect == null && currentSong.Volume < maxVolume) { float currentVolume = currentSong.Volume; currentVolume += (float)gameTime.ElapsedGameTime.TotalMilliseconds / totalFadeTime; currentVolume = Math.Min(currentVolume, maxVolume); currentSong.Volume = currentVolume; } }
public override void Update(GameTime gameTime) { // Nur wenn Komponente aktiviert wurde. if (!Enabled) return; // Nur arbeiten, wenn es eine Welt, einen Player und eine aktive Area gibt. Area nextArea = game.Local.GetCurrentArea(); if (game.Simulation.World == null || game.Local.Player == null || nextArea == null) return; // Reset aller Variablen falls sich der Player ändert if (player != game.Local.Player) { player = game.Local.Player; coins = player.Inventory.Count(i => i is Coin); recoveryTimes.Clear(); } // Reset der Item variablen falls sich die Area ändert if (area != nextArea) { area = nextArea; // Recovery Times recoveryTimes.Clear(); foreach (var item in area.Items.OfType<IAttacker>()) recoveryTimes.Add(item, item.Recovery); // Hitpoints hitpoints.Clear(); foreach (var item in area.Items.OfType<IAttackable>()) hitpoints.Add(item, item.Hitpoints); } // Coins int c = player.Inventory.Count(i => i is Coin); if (coins < c) Play("coin"); coins = c; // Sword foreach (var item in area.Items.OfType<IAttacker>()) { TimeSpan recovery; if (!recoveryTimes.TryGetValue(item, out recovery)) { recovery = item.Recovery; recoveryTimes.Add(item, item.Recovery); } if (recovery < item.Recovery) Play("sword"); recoveryTimes[item] = item.Recovery; } // Hit foreach (var item in area.Items.OfType<IAttackable>()) { int points; if (!hitpoints.TryGetValue(item, out points)) { points = item.Hitpoints; hitpoints.Add(item, item.Hitpoints); } if (points > item.Hitpoints) Play("hit"); hitpoints[item] = item.Hitpoints; } }
/// <summary> /// Sendet einen Area/Inventar-Transfer des angegebenen Items an diesen Client. /// </summary> /// <param name="item">Item.</param> /// <param name="oldArea">Old area.</param> /// <param name="newArea">New area.</param> /// <param name="oldInventory">Old inventory.</param> /// <param name="newInventory">New inventory.</param> public void SendMove(Item item, Area oldArea, Area newArea, IInventory oldInventory, IInventory newInventory) { if (oldArea != null) { if (newArea != null) { // Area to Area // ItemId[int];OldArea[string];NewArea[string] writer.Write((byte)MessageType.ServerMoveAreaToArea); writer.Write((short)0); writer.Write(item.Id); writer.Write(oldArea.Name); writer.Write(newArea.Name); } else { // Area to Inventory // ItemId[int];OldArea[string];InventoryId[int] writer.Write((byte)MessageType.ServerMoveAreaToInventory); writer.Write((short)0); writer.Write(item.Id); writer.Write(oldArea.Name); writer.Write((newInventory as Item).Id); } } else { if (newArea != null) { // Inventory To Area // ItemId[int];InventoryId[int];NewArea[string] writer.Write((byte)MessageType.ServerMoveInventoryToArea); writer.Write((short)0); writer.Write(item.Id); writer.Write((oldInventory as Item).Id); writer.Write(newArea.Name); } else { // Inventory To Inventory // ItemId[int];OldInventoryId[int];NewInventoryId[int] writer.Write((byte)MessageType.ServerMoveInventoryToInventory); writer.Write((short)0); writer.Write(item.Id); writer.Write((oldInventory as Item).Id); writer.Write((newInventory as Item).Id); } } int contentend = (int)writerStream.Position; writerStream.Seek(1, SeekOrigin.Begin); writer.Write((short)(contentend - 3)); writerStream.Seek(contentend, SeekOrigin.Begin); Flush(); }
/// <summary> /// Sendet einen Insert-Auftrag an den Client. /// </summary> /// <param name="item">Item.</param> /// <param name="area">Area.</param> /// <param name="inventory">Inventory.</param> public void SendInsert(Item item, Area area, IInventory inventory) { try { if (area != null) { // Area[string];Type[string];Id[int];Payload[byte[]] writer.Write((byte)MessageType.ServerInsertItemToArea); writer.Write((short)0); writer.Write(area.Name); } else { // InventoryId[int];Type[string];Id[int];Payload[byte[]] writer.Write((byte)MessageType.ServerInsertItemToArea); writer.Write((short)0); writer.Write((inventory as Item).Id); } // Type ermitteln writer.Write(item.GetType().FullName); writer.Write(item.Id); // Payload ermitteln und erstellen item.SerializeInsert(writer); int contentend = (int)writerStream.Position; // Content Länge eintragen writerStream.Seek(1, SeekOrigin.Begin); writer.Write((short)(contentend - 3)); writerStream.Seek(contentend, SeekOrigin.Begin); Flush(); } catch (Exception ex) { Close(ex, false); } }
/// <summary> /// Verarbeitet den Zustandsabgleich eines Items. /// </summary> /// <param name="item">Item referenz</param> /// <param name="area">Area in der das Item liegt (oder null, falls Inventar)</param> /// <param name="inventory">Inventar in dem sich das Item befindet (oder null, falls Area)</param> private void HandleItem(Item item, Area area, IInventory inventory) { ItemCacheEntry entity; if (items.TryGetValue(item.Id, out entity)) { // Frame Update entity.LastUpdate = currentFrame; // Item move if (entity.Area != area || entity.Inventory != inventory) { foreach (var client in clients.ToArray()) client.SendMove(entity.Item, entity.Area, area, entity.Inventory, inventory); entity.Area = area; entity.Inventory = inventory; } // Updates if (currentFrame % KEYFRAME == 0) { // Großes Update foreach (var client in clients.ToArray()) client.SendKeyUpdate(item); } else if (currentFrame % UPDATEFRAME == 0) { // Kleines Update foreach (var client in clients.ToArray()) client.SendUpdate(item); } } else { // Item fehlt -> Insert items.Add(item.Id, new ItemCacheEntry() { Item = item, Area = area, Inventory = inventory, LastUpdate = currentFrame }); foreach (var client in clients.ToArray()) client.SendInsert(item, area, inventory); } }
public abstract void OnUpdate(Area area, GameTime gameTime);
/// <summary> /// Rendert die Spielelemente der aktuellen Szene /// </summary> private void RenderItems(Area area, Point offset, GameTime gameTime) { // Items von hinten nach vorne rendern foreach (var item in area.Items.OrderBy(i => i.Position.Y)) { // Renderer ermitteln und ggf. neu erzeugen ItemRenderer renderer; if (!itemRenderer.TryGetValue(item, out renderer)) { // ACHTUNG: Hier können potentiell neue Items nachträglich hinzu kommen zu denen die Textur noch fehlt // Das muss geprüft und ggf nachgeladen werden. Texture2D texture = GetItemTexture(item.Texture); if (item is Character) renderer = new CharacterRenderer(item as Character, Camera, texture, font); else renderer = new SimpleItemRenderer(item, Camera, texture, font); itemRenderer.Add(item, renderer); } // Ermitteln, ob Item im Interaktionsbereich ist bool highlight = false; if (item is IInteractable && game.Local.Player.InteractableItems.Contains(item as IInteractable) || item is IAttackable && game.Local.Player.AttackableItems.Contains(item as IAttackable)) highlight = true; // Item rendern renderer.Draw(spriteBatch, offset, gameTime, highlight); } // TODO: Nicht mehr verwendete Renderer entfernen }
/// <summary> /// Rendert einen Layer der aktuellen Szene /// </summary> private void RenderLayer(Area area, Layer layer, Point offset) { // TODO: Nur den sichtbaren Bereich rendern for (int x = 0; x < area.Width; x++) { for (int y = 0; y < area.Height; y++) { // Prüfen, ob diese Zelle ein Tile enthält int tileId = layer.Tiles[x, y]; if (tileId == 0) continue; // Tile ermitteln Tile tile = area.Tiles[tileId]; Texture2D texture = GetTileset(tile.Texture); // Position ermitteln int offsetX = (int)(x * Camera.Scale) - offset.X; int offsetY = (int)(y * Camera.Scale) - offset.Y; // Zelle mit der Standard-Textur (Gras) ausmalen spriteBatch.Draw(texture, new Rectangle(offsetX, offsetY, (int)Camera.Scale, (int)Camera.Scale), tile.SourceRectangle, Color.White); } } }
public override void Update(GameTime gameTime) { // Nur wenn Komponente aktiviert wurde. if (!Enabled) return; // Nur arbeiten, wenn es eine Welt, einen Player und eine aktive Area gibt. Area area = game.Local.GetCurrentArea(); if (game.Simulation.World == null || game.Local.Player == null || area == null) return; if (currentArea != area) { // Aktuelle Area wechseln currentArea = area; // Initiale Kameraposition (temporär) Vector2 areaSize = new Vector2(currentArea.Width, currentArea.Height); Camera.SetFocusExplizit(game.Local.Player.Position, areaSize); } // Platziert den Kamerafokus auf den Spieler. Camera.SetFocus(game.Local.Player.Position); }
/// <summary> /// Lädt die angegebene Datei in der Hoffnung um eine Area. /// </summary> public static Area LoadFromJson(string file, ref int nextId) { FileInfo info = new FileInfo(file); using (Stream stream = File.OpenRead(file)) { using (StreamReader sr = new StreamReader(stream)) { // json Datei auslesen string json = sr.ReadToEnd(); // Deserialisieren FileArea result = JsonConvert.DeserializeObject<FileArea>(json); // Neue Area öffnen und mit den Root-Daten füllen FileLayer[] tileLayer = result.layers.Where(l => l.type == "tilelayer").ToArray(); FileLayer objectLayer = result.layers.Where(l => l.type == "objectgroup").FirstOrDefault(); Area area = new Area(tileLayer.Length, result.width, result.height); area.Name = info.Name.Substring(0, info.Name.Length - 5); // Song auslesen if (result.properties != null) area.Song = result.properties.Song; // Hintergrundfarbe interpretieren area.Background = new Color(128, 128, 128); if (!string.IsNullOrEmpty(result.backgroundcolor)) { // Hexwerte als Farbwert parsen area.Background = new Color( Convert.ToInt32(result.backgroundcolor.Substring(1, 2), 16), Convert.ToInt32(result.backgroundcolor.Substring(3, 2), 16), Convert.ToInt32(result.backgroundcolor.Substring(5, 2), 16)); } // Tiles zusammen suchen for (int i = 0; i < result.tilesets.Length; i++) { FileTileset tileset = result.tilesets[i]; int start = tileset.firstgid; int perRow = tileset.imagewidth / tileset.tilewidth; int width = tileset.tilewidth; for (int j = 0; j < tileset.tilecount; j++) { int x = j % perRow; int y = j / perRow; // Block-Status ermitteln bool block = false; if (tileset.tileproperties != null) { FileTileProperty property; if (tileset.tileproperties.TryGetValue(j, out property)) block = property.Block; } // Tile erstellen Tile tile = new Tile() { Texture = tileset.image, SourceRectangle = new Rectangle(x * width, y * width, width, width), Blocked = block }; // In die Auflistung aufnehmen area.Tiles.Add(start + j, tile); } } // TileLayer erstellen for (int l = 0; l < tileLayer.Length; l++) { FileLayer layer = tileLayer[l]; for (int i = 0; i < layer.data.Length; i++) { int x = i % area.Width; int y = i / area.Width; area.Layers[l].Tiles[x, y] = layer.data[i]; } } // Object Layer analysieren if (objectLayer != null) { // Portals - Übertragungspunkte zu anderen Karten foreach (var portal in objectLayer.objects.Where(o => o.type == "Portal")) { Rectangle box = new Rectangle( portal.x / result.tilewidth, portal.y / result.tileheight, portal.width / result.tilewidth, portal.height / result.tileheight ); area.Portals.Add(new Portal() { DestinationArea = portal.name, Box = box }); } // Items (Spielelemente) foreach (var item in objectLayer.objects.Where(o => o.type == "Item")) { Vector2 pos = new Vector2( (item.x + (item.width / 2f)) / result.tilewidth, (item.y + (item.height / 2f)) / result.tileheight); switch (item.name) { case "coin": area.Items.Add(new Coin(nextId++) { Position = pos }); break; case "goldencoin": area.Items.Add(new GoldenCoin(nextId++) { Position = pos }); break; case "decard": area.Items.Add(new Decard(nextId++) { Position = pos }); break; case "heidi": area.Items.Add(new Heidi(nextId++) { Position = pos }); break; case "orc": area.Items.Add(new Orc(nextId++) { Position = pos }); break; case "trader": Trader trader = new Trader(nextId++) { Position = pos }; trader.Inventory.Add(new IronSword(nextId++) { }); trader.Inventory.Add(new WoodSword(nextId++) { }); trader.Inventory.Add(new Gloves(nextId++) { }); area.Items.Add(trader); break; } } // Player (Startpunkte) foreach (var player in objectLayer.objects.Where(o => o.type == "Player")) { Vector2 pos = new Vector2( (player.x + (player.width / 2)) / result.tilewidth, (player.y + (player.height / 2)) / result.tileheight); area.Startpoints.Add(pos); } } return area; } } }