Skip to content

Commit

Permalink
將前端地圖資料抽到後端Server上
Browse files Browse the repository at this point in the history
  • Loading branch information
aa89227 committed Aug 12, 2023
1 parent 7908cea commit 2da5efc
Show file tree
Hide file tree
Showing 25 changed files with 760 additions and 112 deletions.
4 changes: 4 additions & 0 deletions Client/Client.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,9 @@
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="7.0.9" />
<PackageReference Include="MudBlazor" Version="6.4.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\SharedLibrary\SharedLibrary.csproj" />
</ItemGroup>

</Project>
225 changes: 225 additions & 0 deletions Client/Components/BlazorMap.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
using System.ComponentModel;

namespace Client.Components;

public class BlazorMap
{
private readonly int totalWidth;
private readonly int totalHeight;
private readonly int _blockWidth = 133;
private readonly int _blockHeight = 148;
private readonly int _blockMargin = 5;
private readonly Block[][] _blocks;

public int TotalWidth => totalWidth;

public int TotalHeight => totalHeight;

public Block[][] Blocks => _blocks;

public int BlockWidth => _blockWidth;

public int BlockHeight => _blockHeight;

public BlazorMap(SharedLibrary.MonopolyMap data)
{
// 自動Mapping _data 到 _blocks
_blocks = new Block[data.Data.Length][];
for (int i = 0; i < data.Data.Length; i++)
{
_blocks[i] = new Block[data.Data[i].Length];
for (int j = 0; j < data.Data[i].Length; j++)
{
var monopolyBlock = data.Data[i][j];
var x = j * _blockWidth + _blockMargin;
var y = i * _blockHeight + _blockMargin;
_blocks[i][j] = monopolyBlock.Type switch
{
SharedLibrary.BlockType.None => null!,
SharedLibrary.BlockType.Land => new Land(x, y, monopolyBlock.Id, monopolyBlock.ToLand().LandType.ToBlazorLandType()),
SharedLibrary.BlockType.Road => new Road(x, y, monopolyBlock.Id, monopolyBlock.ToRoad().RoadType.ToBlazorRoadType()),
SharedLibrary.BlockType.ParkingLot => new ParkingLot(x, y, monopolyBlock.Id),
SharedLibrary.BlockType.Prison => new Prison(x, y, monopolyBlock.Id),
SharedLibrary.BlockType.StartPoint => new StartPoint(x, y, monopolyBlock.Id),
SharedLibrary.BlockType.Station => new Station(x, y, monopolyBlock.Id, monopolyBlock.ToStation().RoadType.ToBlazorStationRoadType()),
_ => throw new InvalidEnumArgumentException()
};
}
}

totalWidth = data.Data[0].Length * _blockWidth + data.Data[0].Length * _blockMargin - _blockMargin;
totalHeight = data.Data.Length * _blockHeight + data.Data.Length * _blockMargin - _blockMargin;
}

public abstract record Block(int X, int Y, string Id, string ImageName);
private record Road(int X, int Y, string Id, RoadType RoadType) : Block(X, Y, Id, RoadType.GetImageName());
private record Land(int X, int Y, string Id, LandType LandType) : Block(X, Y, Id, LandType.GetImageName());
private record ParkingLot(int X, int Y, string Id) : Block(X, Y, Id, "parkinglot");
private record Prison(int X, int Y, string Id) : Block(X, Y, Id, "prison");
private record StartPoint(int X, int Y, string Id) : Block(X, Y, Id, "startpoint");
private record Station(int X, int Y, string Id, StationRoadType StationRoadType) : Block(X, Y, Id, StationRoadType.GetImageName());

public enum RoadType
{
[ImageName("road_top_left")]
TopLeftIntersection, // ╔
[ImageName("road_top")]
TopIntersection, // ╦
[ImageName("road_top_right")]
TopRightIntersection, // ╗
[ImageName("road_left_center")]
LeftCenterIntersection, // ╠
[ImageName("road_center")]
CenterIntersection, // ╬
[ImageName("road_right_center")]
RightCenterIntersection, // ╣
[ImageName("road_bottom_left")]
BottomLeftIntersection, // ╚
[ImageName("road_bottom")]
BottomIntersection, // ╩
[ImageName("road_bottom_right")]
BottomRightIntersection, // ╝
[ImageName("road_horizontal")]
HorizontalRoad, // ═
[ImageName("road_vertical")]
VerticalRoad // ║
}

public enum StationRoadType
{
[ImageName("railway_top_left")]
TopLeftIntersection, // ╔
[ImageName("railway_top")]
TopIntersection, // ╦
[ImageName("railway_top_right")]
TopRightIntersection, // ╗
[ImageName("railway_left_center")]
LeftCenterIntersection, // ╠
[ImageName("railway_center")]
CenterIntersection, // ╬
[ImageName("railway_right_center")]
RightCenterIntersection, // ╣
[ImageName("railway_bottom_left")]
BottomLeftIntersection, // ╚
[ImageName("railway_bottom")]
BottomIntersection, // ╩
[ImageName("railway_bottom_right")]
BottomRightIntersection, // ╝
[ImageName("railway_horizontal")]
HorizontalRoad, // ═
[ImageName("railway_vertical")]
VerticalRoad // ║
}

public enum LandType
{
[ImageName("land_vertical")]
Right,
[ImageName("land_horizontal")]
Down,
[ImageName("land_vertical")]
Left,
[ImageName("land_horizontal")]
Up
}
}

static class BlazorMapExtensions
{
private static string GetImageName(Type type, Enum enumValue)
{
var memInfo = type.GetMember(enumValue.ToString());
var attributes = memInfo[0].GetCustomAttributes(typeof(ImageNameAttribute), false);
return ((ImageNameAttribute)attributes[0]).ImageName;
}

public static string GetImageName(this BlazorMap.RoadType roadType)
{
return GetImageName(typeof(BlazorMap.RoadType), roadType);
}

public static string GetImageName(this BlazorMap.LandType landType)
{
return GetImageName(typeof(BlazorMap.LandType), landType);
}

public static string GetImageName(this BlazorMap.StationRoadType stationRoadType)
{
return GetImageName(typeof(BlazorMap.StationRoadType), stationRoadType);
}

public static SharedLibrary.Land ToLand(this SharedLibrary.BlockBase block)
{
return (SharedLibrary.Land)block;
}

public static BlazorMap.LandType ToBlazorLandType(this SharedLibrary.LandType landType)
{
return landType switch
{
SharedLibrary.LandType.Right => BlazorMap.LandType.Right,
SharedLibrary.LandType.Down => BlazorMap.LandType.Down,
SharedLibrary.LandType.Left => BlazorMap.LandType.Left,
SharedLibrary.LandType.Up => BlazorMap.LandType.Up,
_ => throw new InvalidEnumArgumentException()
};
}

public static SharedLibrary.Road ToRoad(this SharedLibrary.BlockBase block)
{
return (SharedLibrary.Road)block;
}

public static BlazorMap.RoadType ToBlazorRoadType(this SharedLibrary.RoadType roadType)
{
return roadType switch
{
SharedLibrary.RoadType.TopLeftIntersection => BlazorMap.RoadType.TopLeftIntersection,
SharedLibrary.RoadType.TopIntersection => BlazorMap.RoadType.TopIntersection,
SharedLibrary.RoadType.TopRightIntersection => BlazorMap.RoadType.TopRightIntersection,
SharedLibrary.RoadType.LeftCenterIntersection => BlazorMap.RoadType.LeftCenterIntersection,
SharedLibrary.RoadType.CenterIntersection => BlazorMap.RoadType.CenterIntersection,
SharedLibrary.RoadType.RightCenterIntersection => BlazorMap.RoadType.RightCenterIntersection,
SharedLibrary.RoadType.BottomLeftIntersection => BlazorMap.RoadType.BottomLeftIntersection,
SharedLibrary.RoadType.BottomIntersection => BlazorMap.RoadType.BottomIntersection,
SharedLibrary.RoadType.BottomRightIntersection => BlazorMap.RoadType.BottomRightIntersection,
SharedLibrary.RoadType.HorizontalRoad => BlazorMap.RoadType.HorizontalRoad,
SharedLibrary.RoadType.VerticalRoad => BlazorMap.RoadType.VerticalRoad,
_ => throw new InvalidEnumArgumentException()
};
}

public static SharedLibrary.Station ToStation(this SharedLibrary.BlockBase block)
{
return (SharedLibrary.Station)block;
}

public static BlazorMap.StationRoadType ToBlazorStationRoadType(this SharedLibrary.RoadType stationRoadType)
{
return stationRoadType switch
{
SharedLibrary.RoadType.TopLeftIntersection => BlazorMap.StationRoadType.TopLeftIntersection,
SharedLibrary.RoadType.TopIntersection => BlazorMap.StationRoadType.TopIntersection,
SharedLibrary.RoadType.TopRightIntersection => BlazorMap.StationRoadType.TopRightIntersection,
SharedLibrary.RoadType.LeftCenterIntersection => BlazorMap.StationRoadType.LeftCenterIntersection,
SharedLibrary.RoadType.CenterIntersection => BlazorMap.StationRoadType.CenterIntersection,
SharedLibrary.RoadType.RightCenterIntersection => BlazorMap.StationRoadType.RightCenterIntersection,
SharedLibrary.RoadType.BottomLeftIntersection => BlazorMap.StationRoadType.BottomLeftIntersection,
SharedLibrary.RoadType.BottomIntersection => BlazorMap.StationRoadType.BottomIntersection,
SharedLibrary.RoadType.BottomRightIntersection => BlazorMap.StationRoadType.BottomRightIntersection,
SharedLibrary.RoadType.HorizontalRoad => BlazorMap.StationRoadType.HorizontalRoad,
SharedLibrary.RoadType.VerticalRoad => BlazorMap.StationRoadType.VerticalRoad,
_ => throw new InvalidEnumArgumentException()
};
}
}

[AttributeUsage(AttributeTargets.Field)]
class ImageNameAttribute : Attribute
{
public string ImageName { get; set; }
public ImageNameAttribute(string imageName)
{
ImageName = imageName;
}
}
10 changes: 4 additions & 6 deletions Client/Components/Map.razor
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@

<svg width="50%" height="50%" viewBox="0 0 @width @height" version="1.1"
<svg width="100%" height="100%" viewBox="0 0 @Data.TotalWidth @Data.TotalHeight" version="1.1"
xmlns="http://www.w3.org/2000/svg">
@foreach (var (row, row_index) in Data.Select((item, index) => (row: item, row_index: index)))
@foreach (var (row, row_index) in Data.Blocks.Select((item, index) => (row: item, row_index: index)))
{
@foreach (var (block, index) in row.Select((item, index) => (block: item, index)))
{
var x = index * _blockWidth + index;
var y = row_index * _blockHeight + row_index;
if (block is EmptyBlock)
if (block is null)
{
continue;
}
<image x="@x" y="@y" width="@_blockWidth" height="@_blockHeight" href=@($"./images/gamepage/{block.Image}.svg") />
<image x="@block.X" y="@block.Y" width="@Data.BlockWidth" height="@Data.BlockHeight" href=@($"./images/gamepage/{block.ImageName}.svg") />
}
}
</svg>
102 changes: 2 additions & 100 deletions Client/Components/Map.razor.cs
Original file line number Diff line number Diff line change
@@ -1,106 +1,8 @@
using Microsoft.AspNetCore.Components;

namespace Client.Components;

public partial class Map : ComponentBase
{
private int width = 0;
private int height = 0;
private readonly int _blockWidth = 133;
private readonly int _blockHeight = 148;
private Block[][] Data { get; set; } = null!;
protected override Task OnInitializedAsync()
{
var emptyBlock = new EmptyBlock();
var land = (string id, LandType landType) => new Land(id, landType);
var road = (string id, RoadType roadType) => new Road(id, roadType);
var stationLand = (string id, LandType landType) => new StationLand(id, landType);
var stationRoad = (string id, StationRoadType stationType) => new StationRoad(id, stationType);
Data = new Block[][]
{
new Block[] { emptyBlock, emptyBlock, land("A1", LandType.Down), land("A2", LandType.Down), stationLand("S1", LandType.Down), land("A3", LandType.Down), land("A4", LandType.Down), land("A5", LandType.Down), emptyBlock, emptyBlock, emptyBlock },
new Block[] { emptyBlock, new Start(), road("A1", RoadType.row), road("A2", RoadType.row), stationRoad("S1", StationRoadType.row), road("A3", RoadType.row), road("A4", RoadType.row), road("A5", RoadType.corner_upper_right), emptyBlock, emptyBlock, emptyBlock },
new Block[] { land("E4", LandType.Right), road("E4", RoadType.col), emptyBlock, emptyBlock, land("B1", LandType.Down), land("B2", LandType.Down), land("B3", LandType.Down), road(null, RoadType.col), land("B4", LandType.Down), land("B5", LandType.Down), emptyBlock },
new Block[] { stationLand("S4", LandType.Right), stationRoad("S4", StationRoadType.col), land("E2", LandType.Down), land("E1", LandType.Down), road("B1", RoadType.corner_upper_left), road("B2", RoadType.row), road("B3", RoadType.row), new ParkingLot(), road("B4", RoadType.row), road("B5", RoadType.corner_upper_right), emptyBlock },
new Block[] { land("E3", LandType.Right), road("E3", RoadType.corner_bottom_left), road("E2", RoadType.row), road("E1", RoadType.row), new Prison(), land("C3", LandType.Down), land("S3", LandType.Down), land("C2", LandType.Down), land("C1", LandType.Down), stationRoad("S2", StationRoadType.col), land("S2", LandType.Left) },
new Block[] { emptyBlock, emptyBlock , emptyBlock , land("C4", LandType.Right) , road("C4", RoadType.corner_bottom_left) , road("C3", RoadType.row) , stationRoad("S3", StationRoadType.row), road("C2", RoadType.row), road("C1", RoadType.row) , road(null, RoadType.corner_bottom_right), emptyBlock }
};

// 從Value自動計算地圖大小 每個Block的大小為 133 * 148,間隔 1
width = Data[0].Length * _blockWidth + Data[0].Length - 1;
height = Data.Length * _blockHeight + Data.Length - 1;
return base.OnInitializedAsync();
}

internal abstract record Block(string Id, string? Image = null, string? ImageStyle = null);

internal record EmptyBlock() : Block("Empty Block");

internal record Road(string Id, RoadType RoadType) : Block(Id, $"road_{RoadType}");

internal enum RoadType
{
corner_upper_left, // ╔
//╦
corner_upper_right, // ╗
//╠
//╬
//╣
corner_bottom_left, // ╚
//╩
corner_bottom_right, // ╝
row, // ═
col // ║
}

internal record Land : Block
{
public Land(string Id, LandType LandType) : base(Id)
{
this.Id = Id;
this.LandType = LandType;
switch (LandType)
{
case LandType.Down:
Image = "land_row";
ImageStyle = "padding-top: 84px";
break;
case LandType.Left:
Image = "land_col";
ImageStyle = "padding-right: 37px";
break;
case LandType.Right:
Image = "land_col";
ImageStyle = "padding-left: 37px";
break;
case LandType.Up:
break;
default:
break;
}

}

public string Id { get; }
public LandType LandType { get; }
}
internal enum LandType
{
Right,
Down,
Left,
Up
}

internal record StationRoad(string Id, StationRoadType StationType) : Block(Id, $"railway_{StationType}");
internal enum StationRoadType
{
row,
col,
}

internal record StationLand(string Id, LandType LandType) : Land(Id, LandType);
internal record Start() : Block("Start", "start");
internal record ParkingLot() : Block("ParkingLot", "parking");
internal record Prison() : Block("Prison", "prison");
[Parameter, EditorRequired]
public BlazorMap Data { get; set; } = default!;
}
4 changes: 2 additions & 2 deletions Client/Components/SvgBlock.razor
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<div style="background-image: url('@Image'); width: @Width; height: @Height; transform: scale(@ScaleFactor);">
<div style="background-image: url('@Image'); height: @Height; transform: scale(@ScaleFactor);">
</div>
@code {
[Parameter]
public Block Image { get; set; } = String.Empty;
public string Image { get; set; } = String.Empty;
[Parameter]
public string Width { get; set; } = String.Empty;
[Parameter]
Expand Down
5 changes: 4 additions & 1 deletion Client/Pages/Game.razor
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
@page "/{id}"
@using Client.Components
<Map/>
@if (Data is not null)
{
<Map Data="@Data" />
}
Loading

0 comments on commit 2da5efc

Please sign in to comment.