/// <summary> /// Loads the next node in the given binary reader and returns it. /// </summary> /// <param name="reader">Binary reader to read node from.</param> /// <param name="getProgress">If set to true this node is used to judge the current progress.</param> /// <returns>Scene node that was loaded from the binary reader.</returns> private SceneNode LoadNode(BinaryReader reader, bool getProgress) { // Read in the name of this node's class. string name = reader.ReadString(); //HighPreformanceTimer timer = new HighPreformanceTimer(); // Create a new instance of this entity and tell it to load itself. // (See if its a known object first as its quicker to get it without reflection) SceneNode node = null; if (name.ToLower().EndsWith("binaryphoenix.fusion.engine.entitys.entitynode")) node = new EntityNode(); else if (name.ToLower().EndsWith("binaryphoenix.fusion.engine.entitys.scriptedentitynode")) node = new ScriptedEntityNode(); else if (name.ToLower().EndsWith("binaryphoenix.fusion.engine.scenenode")) node = new SceneNode(); else if (name.ToLower().EndsWith("binaryphoenix.fusion.engine.entitys.groupnode")) node = new GroupNode(); else if (name.ToLower().EndsWith("binaryphoenix.fusion.engine.entitys.emitternode")) node = new EmitterNode(); else if (name.ToLower().EndsWith("binaryphoenix.fusion.engine.entitys.tilemapsegmentnode")) node = new TilemapSegmentNode(); else if (name.ToLower().EndsWith("binaryphoenix.fusion.engine.entitys.pathmarkernode")) node = new PathMarkerNode(); else if (name.ToLower().EndsWith("binaryphoenix.fusion.engine.entitys.tilenode")) node = new TileNode(); else node = (SceneNode)ReflectionMethods.CreateObject(name); //DebugLogger.WriteLog("Created scene graph node " + name + " in " + timer.DurationMillisecond + ".\n"); //timer.Restart(); // Load in this nodes details. node.UniqueID = (_uniqueIDTracker++); node.Load(reader); //DebugLogger.WriteLog("Loaded scene graph node " + name + " in " + timer.DurationMillisecond + ".\n"); // Read in all the children of this node, and attach // them to this node. DebugLogger.IncreaseIndent(); int childCount = reader.ReadInt32(); for (int i = 0; i < childCount; i++) { SceneNode childNode = LoadNode(reader); node.AddChild(childNode); if (getProgress == true) _loadingProgress = (int)(((float)(i + 1) / (float)childCount) * 100.0f); } DebugLogger.DecreaseIndent(); return node; }
/// <summary> /// Preforms a flood fill operation of the given tilemap. /// </summary> /// <param name="tilemapNode">Tilemap to flood fill.</param> /// <param name="x">X position to start flood filling.</param> /// <param name="y">Y position to start flood filling.</param> /// <param name="fillTileset">Tileset to overwrite when flood filling.</param> /// <param name="fillFrame">Frame to overwrite when flood filling.</param> /// <param name="fillTracker">Array to keep track of tiles that have been flooded.</param> /// <param name="selectionX">X position of the tile being used to fill this flood fill step with.</param> /// <param name="selectionY">Y position of the tile being used to fill this flood fill step with.</param> private void FloodFill(TilemapSegmentNode tilemapNode, int x, int y, Tileset fillTileset, int fillFrame, ref bool[,] fillTracker, int selectionX, int selectionY) { // If the selection has gone beyond the width or height of the selection // then wrap it around. if (selectionX < _assetManagerWindow.TilesetSelection.X) selectionX = _assetManagerWindow.TilesetSelection.X + _assetManagerWindow.TilesetSelection.Width - 1; if (selectionX > _assetManagerWindow.TilesetSelection.X + _assetManagerWindow.TilesetSelection.Width - 1) selectionX = _assetManagerWindow.TilesetSelection.X; if (selectionY < _assetManagerWindow.TilesetSelection.Y) selectionY = _assetManagerWindow.TilesetSelection.Y + _assetManagerWindow.TilesetSelection.Height - 1; if (selectionY > _assetManagerWindow.TilesetSelection.Y + _assetManagerWindow.TilesetSelection.Height - 1) selectionY = _assetManagerWindow.TilesetSelection.Y; // Work out the frame of the selection we should be applying to this tile. int selectionFrame = GetSelectedTileset().Image.FrameIndexAtPosition(selectionX * GetSelectedTileset().Image.Width, selectionY * GetSelectedTileset().Image.Height); // If this tile should be set then set it. if (tilemapNode[x, y].Tileset == fillTileset && tilemapNode[x, y].Frame == fillFrame) { tilemapNode[x, y].Tileset = GetSelectedTileset(); tilemapNode[x, y].Frame = selectionFrame; tilemapNode[x, y].Scale(_flipTilesX == true ? -1 : 1, _flipTilesY == true ? -1 : 1, 1); tilemapNode[x, y].Color = _assetManagerWindow.TilesetColor; } // Make this tile as filled. fillTracker[x, y] = true; int tilemapNodeWidth = tilemapNode.Width / tilemapNode.TileWidth; int tilemapNodeHeight = tilemapNode.Height / tilemapNode.TileHeight; // Check the tile to the left of this one, and see if it can be filled. if (x - 1 >= 0 && x - 1 < tilemapNodeWidth && fillTracker[x - 1, y] == false && tilemapNode[x - 1, y].Tileset == fillTileset && tilemapNode[x - 1, y].Frame == fillFrame) FloodFill(tilemapNode, x - 1, y, fillTileset, fillFrame, ref fillTracker, selectionX - 1, selectionY); // Check the tile to the right of this one, and see if it can be filled. if (x + 1 >= 0 && x + 1 < tilemapNodeWidth && fillTracker[x + 1, y] == false && tilemapNode[x + 1, y].Tileset == fillTileset && tilemapNode[x + 1, y].Frame == fillFrame) FloodFill(tilemapNode, x + 1, y, fillTileset, fillFrame, ref fillTracker, selectionX + 1, selectionY); // Check the tile at the top of this one, and see if it can be filled. if (y - 1 >= 0 && y - 1 < tilemapNodeHeight && fillTracker[x, y - 1] == false && tilemapNode[x, y - 1].Tileset == fillTileset && tilemapNode[x, y - 1].Frame == fillFrame) FloodFill(tilemapNode, x, y - 1, fillTileset, fillFrame, ref fillTracker, selectionX, selectionY - 1); // Check the tile at the bottom of this one, and see if it can be filled. if (y + 1 >= 0 && y + 1 < tilemapNodeHeight && fillTracker[x, y + 1] == false && tilemapNode[x, y + 1].Tileset == fillTileset && tilemapNode[x, y + 1].Frame == fillFrame) FloodFill(tilemapNode, x, y + 1, fillTileset, fillFrame, ref fillTracker, selectionX, selectionY + 1); }
/// <summary> /// Inserts the current object into the map at the cursors position (or center-screen - /// - if this is not the active window) at the highest level on the scene graph /// </summary> private void InsertCurrentObject(bool inCenter, string overrideObjectURL) { string objectURL = overrideObjectURL != "" ? overrideObjectURL : _assetManagerWindow.SelectedObjectURL; EntityNode entity = null; // Keep a log of this insertion. DebugLogger.WriteLog("Inserting object of type '" + objectURL + "' into map"); // Check the extension to see if this is a built-in object or not. if (objectURL.IndexOf(".fso") >= 0) { // Compile the script. ScriptCompiler compiler = new ScriptCompiler(); bool errorOccured = false; string errorDescription = "\t"; if (compiler.Compile(objectURL) > 0) foreach (CompileError error in compiler.ErrorList) if (error.AlertLevel == ErrorAlertLevel.Error || error.AlertLevel == ErrorAlertLevel.FatalError) { errorDescription += (errorDescription == "" ? "" : "\n\t") + error.ToString(); errorOccured = true; } // If an error occured notify the user if not then // insert a new scripted entity into the map. if (errorOccured == true) { MessageBox.Show("Unable to insert object into map, the following error(s) occured while attempt to compile this objects script.\n\n"+errorDescription,"Compile Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); DebugLogger.WriteLog("Object insertion aborted. The following error(s) occured while attempting to compile this objects script.\n\n" + errorDescription, LogAlertLevel.Warning); } else { // Dump the compiled code into a memory stream. MemoryStream memStream = new MemoryStream(); BinaryWriter writer = new BinaryWriter(memStream); BinaryReader reader = new BinaryReader(memStream); compiler.DumpExecutableFile(writer); memStream.Position = 0; // Create a new scripted entity with the given script attached to it. ScriptedEntityNode scriptedEntity = new ScriptedEntityNode(); entity = scriptedEntity; entity.RenderMode = EntityRenderMode.Rectangle; entity.BoundingRectangle = new Rectangle(0, 0, 16, 16); entity.Width = 16; entity.Height = 16; entity.Name = Path.GetFileNameWithoutExtension(objectURL); ScriptProcess process = new ScriptProcess(VirtualMachine.GlobalInstance, reader); process.Url = objectURL; if (process.DefaultEditorState != null) process.ChangeState(process.DefaultEditorState.Identifier); else process.State = null; scriptedEntity.ScriptProcess = process; // Are we allowed to place the entity? bool canPlace = true; string placeError = "This entity has been flagged as unplaceable. Please choose another or check this objects script."; foreach (Define define in process.Defines) { switch (define.Ident.ToUpper()) { case "UNPLACEABLE": canPlace = false; break; case "UNPLACEABLE_ERROR": placeError = define.Value; break; } } if (canPlace == false) { MessageBox.Show(placeError, "Unplaceable", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } Engine.Engine.GlobalInstance.Map.SceneGraph.RootNode.AddChild(entity); // Invoke OnCreate event. scriptedEntity.ScriptProcess[0].InvokeFunction("OnCreate", true, false); // Free up the streams. memStream.Close(); reader.Close(); writer.Close(); } } // Its built in so create the object requested. else { switch (objectURL.ToLower()) { case "tilemap segment": TilemapSegmentNode segment = new TilemapSegmentNode(8, 8, 16, 16); Engine.Engine.GlobalInstance.Map.SceneGraph.RootNode.AddChild(segment); segment.IsGridVisible = true; entity = segment; break; case "emitter": entity = new EmitterNode(); Engine.Engine.GlobalInstance.Map.SceneGraph.RootNode.AddChild(entity); entity.BoundingRectangle = new Rectangle(0, 0, 16, 16); entity.Width = 16; entity.Height = 16; break; case "entity": entity = new EntityNode(); Engine.Engine.GlobalInstance.Map.SceneGraph.RootNode.AddChild(entity); entity.BoundingRectangle = new Rectangle(0, 0, 16, 16); entity.Width = 16; entity.Height = 16; break; case "path marker": entity = new PathMarkerNode(); Engine.Engine.GlobalInstance.Map.SceneGraph.RootNode.AddChild(entity); entity.BoundingRectangle = new Rectangle(0, 0, 16, 16); entity.Width = 16; entity.Height = 16; entity.Image = _pathMarkerImage; entity.RenderMode = EntityRenderMode.Image; entity.Name = "Path Marker " + MathMethods.Random(MathMethods.Random(0, 10000), MathMethods.Random(10000, 10000000)); foreach (EntityNode selEntity in _selectedEntityList) if (selEntity is PathMarkerNode && ((PathMarkerNode)selEntity).NextNodeName == "") { ((PathMarkerNode)selEntity).NextNode = (PathMarkerNode)entity; ((PathMarkerNode)selEntity).NextNodeName = entity.Name; } break; } } if (entity == null) return; // Find the correct position for our new entity. int mapX, mapY; if (inCenter == false) { mapX = (int)Editor.GlobalInstance.CameraNode.Transformation.X + (int)((mousePositionBeforeRightClick[0] / Editor.GlobalInstance.CameraNode.Zoom)); mapY = (int)Editor.GlobalInstance.CameraNode.Transformation.Y + (int)((mousePositionBeforeRightClick[1] / Editor.GlobalInstance.CameraNode.Zoom)); } else { mapX = (int)Editor.GlobalInstance.CameraNode.Transformation.X + (int)(((mapPanel.ClientSize.Width - entity.BoundingRectangle.Width) / 2) / Editor.GlobalInstance.CameraNode.Zoom); mapY = (int)Editor.GlobalInstance.CameraNode.Transformation.Y + (int)(((mapPanel.ClientSize.Height - entity.BoundingRectangle.Height) / 2) / Editor.GlobalInstance.CameraNode.Zoom); } if (_snapToGrid == true) { mapX = (mapX / _gridWidth) * _gridWidth; mapY = (mapY / _gridHeight) * _gridHeight; } entity.Position(mapX, mapY, 0.0f); entity.IsBoundingBoxVisible = _viewBoundingBoxs; entity.IsEventLinesVisible = _viewEventLines; entity.IsCollisionBoxVisible = _viewCollisionBoxs; entity.ForceVisibility = true; ClearSelection(); AddEntityToSelection(entity); // Update the scene graph window if it exists. if (_sceneGraphWindow != null) _sceneGraphWindow.SyncronizeData(); // Update this entitys event nodes and the event nodes of others. foreach (SceneNode node in Engine.Engine.GlobalInstance.Map.SceneGraph.EnumerateNodes()) { EntityNode subNode = node as EntityNode; if (subNode == null) continue; if (subNode.Event.ToLower() == entity.Name.ToString().ToLower()) subNode.EventNodes.Add(entity); } PushUndoOperation(new InsertNodesUndoOperation(new SceneNode[] { entity })); SyncronizeWindow(); _mapChangedSinceSave = true; }
public void CreateTilemap(ScriptThread thread) { EntityNode node = new TilemapSegmentNode(); thread.SetReturnValue(new SceneNodeScriptObject(node)); }