コード例 #1
0
        static IFastImage Visualize(CellBoard board, bool showOnlyLargestArea, int scale = 1)
        {
            if (showOnlyLargestArea)
            {
                var(area, size) =
                    ConnectedAreaAnalyzer
                    .FindForegroundAreas(board.Dimensions, p => board[p] == CellType.Dead)
                    .MaxBy(component => component.Area)
                    ?.TrimExcess(1) ??
                    throw new InvalidOperationException("This can't happen");

                return(GenericVisualizer.RenderBinary(size,
                                                      isTrue: area.Contains,
                                                      trueColor: SKColors.White,
                                                      falseColor: SKColors.Black,
                                                      scale: scale));
            }
            else
            {
                return(GenericVisualizer.RenderBinary(board.Dimensions,
                                                      isTrue: p => board[p] == CellType.Dead,
                                                      trueColor: SKColors.White,
                                                      falseColor: SKColors.Black,
                                                      scale: scale));
            }
        }
コード例 #2
0
    public static MapData Create(int seed, TextureQueue textureQueue)
    {
        GC.KeepAlive(textureQueue); // SHUT UP ABOUT UNUSED PARAMETER!!
        var random = new Random(seed);

        CellBoard geometryBoard = GenerateGeometryBoard(random);

        (ConnectedArea playableSpace, Size boardSize) = geometryBoard.TrimToLargestDeadConnectedArea();

        var internalDistances = playableSpace.DetermineInteriorEdgeDistance(Neighborhood.Moore);

        var sideDefCache = new ModelSequence <SideDef, SideDef>(s => s); // Seems silly, but what should be abstracted about it?
        var vertexCache  = new ModelSequence <LatticePoint, Vertex>(ConvertToVertex);
        var sectorCache  = new ModelSequence <SectorDescription, Sector>(ConvertToSector);
        var lineCache    = new ModelSequence <LineDescription, LineDef>(ld => ConvertToLineDef(ld, sectorCache, sideDefCache));

        var edges = GetEdges(boardSize, internalDistances);

        DrawEdges(edges, vertexCache, lineCache);

        var playerLogicalSpot = FindPlayerSpot(geometryBoard);

        return(new MapData(
                   NameSpace: "Doom",
                   LineDefs: lineCache.GetDefinitions().ToImmutableArray(),
                   SideDefs: sideDefCache.GetDefinitions().ToImmutableArray(),
                   Vertices: vertexCache.GetDefinitions().ToImmutableArray(),
                   Sectors: sectorCache.GetDefinitions().ToImmutableArray(),
                   Things: ImmutableArray.Create(
                       Actor.Player1Start.MakeThing(
                           x: playerLogicalSpot.X * LogicalUnitSize + LogicalUnitSize / 2,
                           y: playerLogicalSpot.Y * LogicalUnitSize + LogicalUnitSize / 2,
                           angle: 90))));
    }
コード例 #3
0
 void Initialize(CellBoard cellBoard)
 {
     Cells = TwoDimensionalArrayExtension.Create <CellView>(cellBoard.ActualCells.Size());
     cellBoard.ActualCells.ForEach((point, cell) => {
         var cellView = new CellView {
             Point = point, DataContext = cell
         };
         cellView.IndexChanged += OnCellViewIndexChanged;
         Cells.Set(point, cellView);
     });
 }
コード例 #4
0
    void Awake()
    {
        //Ensureses that the cell manager has started
        if (instance == null)
        {
            instance = this;
        }
        else if (instance != this)
        {
            Destroy(gameObject);
        }

        cellB = GetComponent <CellBoard>();//Gets the cell board component
    }
コード例 #5
0
        static void Main(string[] args)
        {
            var grid = new CellBoard(10, 10);

            grid.Randomize();

            ShowGrid(grid.CurrentCellState);

            while (Console.ReadLine() != "q")
            {
                grid.UpdateState();
                ShowGrid(grid.CurrentCellState);
            }
        }
コード例 #6
0
    public void Setup()
    {
        var random = new Random(3);
        var board  =
            new CellBoard(new Size(256, 256))
            .Fill(random, probabilityAlive: 0.5)
            .MakeBorderAlive(thickness: 1)
            .GenerateStandardCave()
            .ScaleAndSmooth(times: 3)
            .TrimToLargestDeadArea();

        _area = ConnectedAreaAnalyzer
                .FindForegroundAreas(board.Dimensions, p => board[p] == CellType.Dead)
                .MaxBy(a => a.Area);
    }
コード例 #7
0
        public void ScaleBoard()
        {
            var dir = OutputLocation.CreateDirectory("Cellular Automata Scaling");

            foreach (var file in dir.GetFiles())
            {
                file.Delete();
            }

            var path = dir.FullName;

            void Save(CellBoard board, string name, int scale)
            {
                using var img = Visualize(board, false, scale);
                img.Save(Path.Combine(path, $"{name}.png"));
            }

            var random = new Random(0);

            var board =
                new CellBoard(new Size(128, 128))
                .Fill(random, probabilityAlive: 0.5)
                .MakeBorderAlive(thickness: 1)
                .GenerateStandardCave();

            Save(board, "1. board", 8);

            const int scalingIterations = 3;

            CellBoard last = board;

            foreach (var noise in new[] { 0, 0.05, 0.1, 0.15, 0.2 })
            {
                CellBoard scaled = board;

                foreach (int scalingIteration in Enumerable.Range(1, scalingIterations))
                {
                    scaled = scaled.Quadruple().AddNoise(random, noise).RunGenerations(1);

                    Save(scaled, $"{scalingIteration + 1}. board {1 << scalingIteration}x - noise {noise:F2}", 8 / (1 << scalingIteration));

                    last = scaled;
                }
            }
        }
コード例 #8
0
        public void RenderABunchOfOptions()
        {
            var dir = OutputLocation.CreateDirectory("Cellular Automata Trials");

            foreach (var file in dir.GetFiles())
            {
                file.Delete();
            }

            var path = dir.FullName;

            var trials =
                (from seed in Enumerable.Range(0, 3)
                 from size in new[] { 96, 128 }
                 from probAlive in new[] { 0.48, 0.5, 0.52 }
                 select(seed, size, probAlive)).ToArray();

            Parallel.ForEach(trials, trial =>
            {
                var random = new Random(trial.seed);

                var board =
                    new CellBoard(new Size(trial.size, trial.size))
                    .Fill(random, probabilityAlive: trial.probAlive)
                    .MakeBorderAlive(thickness: 1)
                    .GenerateStandardCave()
                    .TrimToLargestDeadArea()
                    .ScaleAndSmooth()
                    .ScaleAndSmooth();

                using var img = Visualize(board, showOnlyLargestArea: false);

                img.Save(Path.Combine(path, $"Size {trial.size}" +
                                      $" - ProbAlive {trial.probAlive:F2}" +
                                      $" - Seed {trial.seed}" +
                                      $".png"));
            });
        }
コード例 #9
0
 static IFastImage Visualize(CellBoard board, int scale = 1) =>
 GenericVisualizer.RenderBinary(board.Dimensions,
                                isTrue: p => board[p] == CellType.Dead,
                                trueColor: SKColors.White,
                                falseColor: SKColors.Black,
                                scale: scale);
コード例 #10
0
    public static MapData Create(int seed, string texturePrefix, TextureQueue textureQueue)
    {
        var random = new Random(seed);

        var caveBoard =
            new CellBoard(new Size(128, 128))
            .Fill(random, probabilityAlive: 0.5)
            .MakeBorderAlive(thickness: 3)
            .GenerateStandardCave();

        var(caveArea, size) =
            ConnectedAreaAnalyzer
            .FindForegroundAreas(caveBoard.Dimensions, p => caveBoard[p] == CellType.Dead)
            .OrderByDescending(a => a.Area)
            .First()
            .TrimExcess(border: 1);

        var interior = caveArea.DetermineInteriorEdgeDistance(Neighborhood.VonNeumann);

        var alternateFloor =
            new CellBoard(new Size(size.Width + 1, size.Height + 1))
            .Fill(random, probabilityAlive: 0.5)
            .RunGenerations(6);
        var alternateCeiling =
            new CellBoard(new Size(size.Width + 1, size.Height + 1))
            .Fill(random, probabilityAlive: 0.5)
            .RunGenerations(6);

        var lightRange = new LightRange(DarkLevels: 15, LightLevels: 5);
        var lights     = CaveThingPlacement.RandomlyPlaceLights(
            interior.Where(pair => pair.Value == 2).Select(pair => pair.Key).ToList(),
            random,
            lightRange,
            percentAreaToCover: 0.05,
            varyHeight: true)
                         .ToArray();

        var(floorLighting, ceilingLighting) =
            LightTracer.Trace(size, p => !caveArea.Contains(p), lightRange, lights);

        var(planeMap, sectors, tiles) =
            CreateGeometry(
                size,
                caveArea,
                alternateFloor,
                alternateCeiling,
                floorLighting,
                ceilingLighting,
                textureQueue,
                texturePrefix);

        var playerPosition = caveArea.First();

        var things =
            lights.Select(light => new Thing(
                              Type: light.Height == LightHeight.Ceiling ? "CeilingCrystal" : "FloorCrystal",
                              X: light.Center.X + 0.5,
                              Y: light.Center.Y + 0.5,
                              Z: 0,
                              Angle: 0,
                              Ambush: false,
                              Skill1: true,
                              Skill2: true,
                              Skill3: true,
                              Skill4: true)).ToList();

        things.Add(new Thing(
                       Type: Actor.Player1Start.ClassName,
                       X: playerPosition.X + 0.5,
                       Y: playerPosition.Y + 0.5,
                       Z: 0,
                       Angle: 0,
                       Ambush: false,
                       Skill1: true,
                       Skill2: true,
                       Skill3: true,
                       Skill4: true));


        return(new MapData(
                   NameSpace: "Wolf3D",
                   TileSize: 64,
                   Name: "Procedural Cave",
                   Width: size.Width,
                   Height: size.Height,
                   Tiles: tiles,
                   Sectors: sectors,
                   Zones: ImmutableArray.Create(new Zone()),
                   Planes: ImmutableArray.Create(new Plane(Depth: 64)),
                   PlaneMaps: ImmutableArray.Create(planeMap),
                   Things: things.ToImmutableArray(),
                   Triggers: ImmutableArray <Trigger> .Empty));
    }
コード例 #11
0
    static (ImmutableArray <MapSquare>, ImmutableArray <Sector>, ImmutableArray <Tile>) CreateGeometry(
        Size size,
        ConnectedArea cave,
        CellBoard alternateFloor,
        CellBoard alternateCeiling,
        LightMap floorLight,
        LightMap ceilingLight,
        TextureQueue textureQueue,
        string texturePrefix)
    {
        var planeMap = new Canvas(size);

        double minLight  = 0.2;
        double darkStep  = (1 - minLight) / ceilingLight.Range.DarkLevels;
        double maxLight  = 1.1;
        double lightStep = (maxLight - 1) / ceilingLight.Range.LightLevels;


        double GetAlpha(int light) =>
        light switch
        {
            0 => 0,
            int pos when pos > 0 => pos * lightStep,
            int neg when neg < 0 => - neg * darkStep,
            _ => throw new InvalidOperationException("Impossible")
        };


        string GetTextureName(Corners corners, int light, bool isEastWest = false)
        {
            string name = $"t{(int)corners:D2}{light:+#;-#;#}{(isEastWest ? "dark" : "")}";

            var patches = ImmutableArray.CreateBuilder <Patch>();

            if (light > 0)
            {
                patches.Add(
                    new Patch(
                        $"{texturePrefix}{(int)corners:D2}",
                        0,
                        0,
                        Blend: new ColorBlend("FFFFFF", GetAlpha(light))));
            }
            else if (light < 0)
            {
                patches.Add(
                    new Patch(
                        $"{texturePrefix}{(int)corners:D2}",
                        0,
                        0,
                        Blend: new ColorBlend("000000", GetAlpha(light))));
            }
            else
            {
                patches.Add(
                    new Patch(
                        $"{texturePrefix}{(int)corners:D2}",
                        0,
                        0));
            }

            if (isEastWest)
            {
                patches.Add(
                    new Patch(
                        $"{texturePrefix}{(int)corners:D2}",
                        0,
                        0,
                        Blend: new ColorBlend("000000"),
                        Style: RenderStyle.Translucent,
                        Alpha: 0.075));
            }

            textureQueue.Add(new CompositeTexture(name, 256, 256, patches.ToImmutable(), XScale: 4, YScale: 4));
            return(name);
        }

        Corners GetCorners(CellBoard board, Position pos) => Corner.CreateFromUpperLeft(
            upperLeft: pos, on: p => board[p] == CellType.Dead);

        Corners GetSideCorners(Position left, Position right) => Corner.Create(
            topLeft: alternateCeiling[left] == CellType.Dead,
            topRight: alternateCeiling[right] == CellType.Dead,
            bottomLeft: alternateFloor[left] == CellType.Dead,
            bottomRight: alternateFloor[right] == CellType.Dead
            );

        int GetSideLight(Position p) => (ceilingLight[p] + floorLight[p]) / 2;

        var sectorSequence = new ModelSequence <SectorDescription, Sector>(description =>
                                                                           new Sector(
                                                                               TextureCeiling: GetTextureName(description.Ceiling, description.CeilingLight),
                                                                               TextureFloor: GetTextureName(description.Floor, description.FloorLight)));
        var tileSequence = new ModelSequence <TileDescription, Tile>(description =>
                                                                     new Tile(
                                                                         TextureEast: GetTextureName(description.EastCorners, description.EastLight, isEastWest: true),
                                                                         TextureNorth: GetTextureName(description.NorthCorners, description.NorthLight),
                                                                         TextureWest: GetTextureName(description.WestCorners, description.WestLight, isEastWest: true),
                                                                         TextureSouth: GetTextureName(description.SouthCorners, description.SouthLight),
                                                                         TextureOverhead: GetTextureName(description.FloorCorners, 0)));

        for (int y = 0; y < size.Height; y++)
        {
            for (int x = 0; x < size.Width; x++)
            {
                var pos = new Position(x, y);

                int tileId = -1;
                if (!cave.Contains(pos))
                {
                    tileId = tileSequence.GetIndex(new TileDescription(
                                                       NorthCorners: GetSideCorners(left: pos + Offset.Right, right: pos),
                                                       EastCorners: GetSideCorners(left: pos + Offset.DownAndRight, right: pos + Offset.Right),
                                                       SouthCorners: GetSideCorners(left: pos + Offset.Down, right: pos + Offset.DownAndRight),
                                                       WestCorners: GetSideCorners(left: pos, right: pos + Offset.Down),
                                                       FloorCorners: GetCorners(alternateFloor, pos),
                                                       NorthLight: GetSideLight(pos + Offset.Up),
                                                       EastLight: GetSideLight(pos + Offset.Right),
                                                       SouthLight: GetSideLight(pos + Offset.Down),
                                                       WestLight: GetSideLight(pos + Offset.Left)));
                }

                int sectorId = sectorSequence.GetIndex(new SectorDescription(
                                                           Floor: GetCorners(alternateFloor, pos),
                                                           Ceiling: GetCorners(alternateCeiling, pos),
                                                           FloorLight: floorLight[pos],
                                                           CeilingLight: ceilingLight[pos]));

                planeMap.Set(x, y,
                             tile: tileId,
                             sector: sectorId,
                             zone: 0);
            }
        }

        return(
            planeMap.ToPlaneMap(),
            sectorSequence.GetDefinitions().ToImmutableArray(),
            tileSequence.GetDefinitions().ToImmutableArray());
    }
コード例 #12
0
 //script used upon awakening
 private void Awake()
 {
     cellB          = GameManager.instance.GetComponent <CellBoard>(); //Sets an instance of the cell board
     cellMatrix     = cellB.cellMatrix;                                //Declares a cell matrix to establish a position for each individual cell
     spriteRenderer = GetComponent <SpriteRenderer>();                 //Sets a sprite renderer to create visuals
 }