Changed Player class to inherit from Grid
Added .gif support
This commit is contained in:
parent
70ca03a101
commit
34db81f143
@ -42,13 +42,28 @@
|
||||
<UniformGrid x:Name="LoadedSprites" Columns="6" Margin="2,0,2,0" Rows="6" MinHeight="120" />
|
||||
</StackPanel>
|
||||
<Border Grid.Column="1" BorderThickness="1,1,1,1" BorderBrush="DarkGray" Background="#19000000">
|
||||
<ListView x:Name="PlayersList" Background="{x:Null}">
|
||||
<ListView.View>
|
||||
<GridView>
|
||||
<GridViewColumn/>
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
</ListView>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition MinHeight="400"/>
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<ListView x:Name="PlayersList" Background="{x:Null}">
|
||||
<ListView.View>
|
||||
<GridView>
|
||||
<GridViewColumn/>
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
</ListView>
|
||||
<Image x:Name="MouseOverViewImage" Grid.Row="1"/>
|
||||
<Rectangle x:Name="test" HorizontalAlignment="Left" Height="100" Margin="145,96,0,0" Grid.Row="1" Stroke="Black" VerticalAlignment="Top" Width="100">
|
||||
<Rectangle.Fill>
|
||||
<RadialGradientBrush>
|
||||
<GradientStop Color="White"/>
|
||||
<GradientStop Color="Transparent" Offset="1"/>
|
||||
</RadialGradientBrush>
|
||||
</Rectangle.Fill>
|
||||
</Rectangle>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
<Grid Grid.Column="1" VerticalAlignment="Center">
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Microsoft.Win32;
|
||||
using RBG.Helpers;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
@ -72,9 +73,7 @@ namespace RBG_Server.WPF
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates and starts the game server
|
||||
@ -154,22 +153,17 @@ namespace RBG_Server.WPF
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates elements to go inside the game grid from the provided list of players
|
||||
/// Generates the game board overlay grid
|
||||
/// The grid should be appropriately sized before using this
|
||||
/// </summary>
|
||||
private void GenerateGameBoard(List<Player> players)
|
||||
{
|
||||
SolidColorBrush buttonBrush = new(Color.FromArgb(1, 255, 255, 255));
|
||||
Grid[] cells = new Grid[PreviewImageOverlay.RowDefinitions.Count * PreviewImageOverlay.ColumnDefinitions.Count];
|
||||
// Create an array of BoardCells Rows*Columns in size
|
||||
BoardCell[] cells = new BoardCell[PreviewImageOverlay.RowDefinitions.Count * PreviewImageOverlay.ColumnDefinitions.Count];
|
||||
List<Player> unaddedPlayers = players;
|
||||
for (int i = 0; i < cells.Length; i++)
|
||||
{
|
||||
cells[i] = new Grid();
|
||||
// Each cell has several components:
|
||||
// Stackpanel, which has each sprite in the cell
|
||||
UniformGrid cellStack = new();
|
||||
cellStack.Columns = 4;
|
||||
//cellStack.ItemWidth = cellStack.Width / 4;
|
||||
cells[i] = new BoardCell();
|
||||
Queue<Player> removedPlayers = new();
|
||||
foreach (Player item in unaddedPlayers)
|
||||
{
|
||||
@ -182,50 +176,66 @@ namespace RBG_Server.WPF
|
||||
{
|
||||
Player removed = removedPlayers.Dequeue();
|
||||
_ = unaddedPlayers.Remove(removed);
|
||||
_ = cellStack.Children.Add(removed);
|
||||
_ = cells[i].CellStack.Children.Add(removed);
|
||||
}
|
||||
_ = cells[i].Children.Add(cellStack);
|
||||
// Button, whose content is empty
|
||||
Button cellButton = new()
|
||||
{
|
||||
Content = ""
|
||||
};
|
||||
cellButton.Background = buttonBrush;
|
||||
cellButton.Tag = new Tuple<int, int>(i / PreviewImageOverlay.ColumnDefinitions.Count, i % PreviewImageOverlay.ColumnDefinitions.Count); // Tag is a Tuple<row, column>
|
||||
cellButton.Click += CellButton_Click;
|
||||
_ = cells[i].Children.Add(cellButton);
|
||||
_ = PreviewImageOverlay.Children.Add(cells[i]);
|
||||
cells[i].CellButton.Tag = new Tuple<int, int>(i % PreviewImageOverlay.ColumnDefinitions.Count, i / PreviewImageOverlay.ColumnDefinitions.Count);
|
||||
Grid.SetColumn(cells[i], i % PreviewImageOverlay.ColumnDefinitions.Count);
|
||||
Grid.SetRow(cells[i], i / PreviewImageOverlay.ColumnDefinitions.Count);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Represents a cell on the board
|
||||
/// Represents a cell on the board; as a grid
|
||||
/// </summary>
|
||||
class BoardCell
|
||||
class BoardCell : Grid
|
||||
{
|
||||
// brush the button should have
|
||||
|
||||
static SolidColorBrush buttonBrush = new(Color.FromArgb(1, 255, 255, 255));
|
||||
|
||||
|
||||
// Each cell has a uniform grid that
|
||||
UniformGrid cellStack = new()
|
||||
public UniformGrid CellStack { get; } = new()
|
||||
{
|
||||
Columns = 4,
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
VerticalAlignment = VerticalAlignment.Stretch
|
||||
};
|
||||
Button cellButton = new()
|
||||
public Button CellButton { get; } = new()
|
||||
{
|
||||
Content = ""
|
||||
Content = "",
|
||||
};
|
||||
Queue<Player> removedPlayers = new();
|
||||
Grid parentGrid;
|
||||
// Grid parentGrid; // Parent grid is now this itself
|
||||
|
||||
public BoardCell(Grid parentGrid)
|
||||
public BoardCell() : base()
|
||||
{
|
||||
this.parentGrid = parentGrid;
|
||||
CellButton.MouseEnter += CellButton_MouseEnter;
|
||||
CellButton.MouseLeave += CellButton_MouseLeave;
|
||||
CellButton.Click += CellButton_Click;
|
||||
CellButton.Background = buttonBrush;
|
||||
CellStack.Columns = 2;
|
||||
CellStack.VerticalAlignment = VerticalAlignment.Top;
|
||||
// Add our grid and button
|
||||
_ = Children.Add(CellStack);
|
||||
_ = Children.Add(CellButton);
|
||||
}
|
||||
|
||||
private void CellButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Button cellButton = sender as Button;
|
||||
System.Diagnostics.Debug.WriteLine("Button at {0}, {1} was clicked", ((Tuple<int, int>)cellButton.Tag).Item2, ((Tuple<int, int>)cellButton.Tag).Item1);
|
||||
}
|
||||
|
||||
private void CellButton_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
|
||||
{
|
||||
//throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void CellButton_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
|
||||
{
|
||||
//throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateNewGameBoard(List<Player> players)
|
||||
@ -239,11 +249,7 @@ namespace RBG_Server.WPF
|
||||
}
|
||||
}
|
||||
|
||||
private void CellButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Button cellButton = sender as Button;
|
||||
Console.WriteLine("Button at {0}, {1} was clicked", ((Tuple<int, int>)cellButton.Tag).Item2, ((Tuple<int, int>)cellButton.Tag).Item1);
|
||||
}
|
||||
|
||||
|
||||
private void Sliders_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
|
||||
{
|
||||
@ -275,26 +281,68 @@ namespace RBG_Server.WPF
|
||||
// Create a new player at a random location
|
||||
Player p = new("Player " + i, rand.Next(0, PreviewImageOverlay.RowDefinitions.Count), rand.Next(PreviewImageOverlay.ColumnDefinitions.Count));
|
||||
// Load the sprite
|
||||
BitmapSource pSprite = new BitmapImage(new Uri("pack://application:,,,/Sprites/" + sprites[rand.Next(0, sprites.Length)]));
|
||||
// Recolour:
|
||||
if (rand.Next(1, 4) == 1)
|
||||
string[] keys = new string[loadedSprites.Count];
|
||||
loadedSprites.Keys.CopyTo(keys, 0);
|
||||
string key = keys[rand.Next(keys.Length)];
|
||||
if (key.ToLower().EndsWith(".gif"))
|
||||
{
|
||||
pSprite = RBG.Helpers.ImageProcessing.UpdatePixelColours(pSprite, 0.0, 0.0, 1.0);
|
||||
try
|
||||
{
|
||||
AnimatedBitmapImage animatedBitmap = new(new MemoryStream(loadedSprites[key]), p.PlayerSprite, Application.Current.Dispatcher);
|
||||
}
|
||||
catch
|
||||
{
|
||||
BitmapSource pSprite;
|
||||
{
|
||||
// Scope & create the base data for pSprite
|
||||
BitmapImage src = new();
|
||||
src.BeginInit();
|
||||
|
||||
src.StreamSource = new MemoryStream(loadedSprites[key]);
|
||||
src.EndInit();
|
||||
pSprite = src;
|
||||
}
|
||||
// Recolour:
|
||||
if (rand.Next(1, 4) == 1)
|
||||
{
|
||||
pSprite = ImageProcessing.UpdatePixelColours(pSprite, 0.0, 0.0, 1.0);
|
||||
}
|
||||
p.PlayerSprite.Source = pSprite;
|
||||
|
||||
}
|
||||
}
|
||||
p.Source = pSprite;
|
||||
else
|
||||
{
|
||||
BitmapSource pSprite;
|
||||
{
|
||||
// Scope & create the base data for pSprite
|
||||
BitmapImage src = new();
|
||||
src.BeginInit();
|
||||
src.StreamSource = new MemoryStream(loadedSprites[key]);
|
||||
src.EndInit();
|
||||
pSprite = src;
|
||||
}
|
||||
// Recolour:
|
||||
if (rand.Next(1, 4) == 1)
|
||||
{
|
||||
pSprite = ImageProcessing.UpdatePixelColours(pSprite, 0.0, 0.0, 1.0);
|
||||
}
|
||||
p.PlayerSprite.Source = pSprite;
|
||||
}
|
||||
|
||||
randPlayers.Add(p);
|
||||
}
|
||||
|
||||
GenerateGameBoard(randPlayers);
|
||||
}
|
||||
|
||||
ConcurrentDictionary<string, MemoryStream> loadedSprites = new();
|
||||
ConcurrentDictionary<string, byte[]> loadedSprites = new();
|
||||
Task loadingFiles;
|
||||
|
||||
private void GameSpritesBrowser_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
OpenFileDialog ofd = new();
|
||||
ofd.Filter = "Image Files|*.png;*.jpg";
|
||||
ofd.Filter = "Image Files|*.png;*.jpg;*.gif";
|
||||
ofd.Multiselect = true;
|
||||
if (ofd.ShowDialog() == true)
|
||||
{
|
||||
@ -327,23 +375,57 @@ namespace RBG_Server.WPF
|
||||
{
|
||||
fs.CopyTo(ms);
|
||||
}
|
||||
_ = loadedSprites.TryAdd(file, ms);
|
||||
_ = loadedSprites.TryAdd(file, ms.ToArray());
|
||||
});
|
||||
// Invoke the dispatcher to add all of the sprites to the loaded sprites list
|
||||
_ = Application.Current.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Render, new Action(() =>
|
||||
{
|
||||
LoadedSprites.Children.Clear();
|
||||
foreach (KeyValuePair<string, MemoryStream> item in loadedSprites)
|
||||
foreach (KeyValuePair<string, byte[]> item in loadedSprites)
|
||||
{
|
||||
BitmapImage image = new();
|
||||
image.BeginInit();
|
||||
image.StreamSource = item.Value;
|
||||
image.EndInit();
|
||||
Image spriteImage = new()
|
||||
if (item.Key.ToLower().EndsWith(".gif"))
|
||||
{
|
||||
Source = image
|
||||
};
|
||||
_ = LoadedSprites.Children.Add(spriteImage);
|
||||
try
|
||||
{
|
||||
/*
|
||||
// Must write-out the stream to
|
||||
MediaElement gifMedia = new();
|
||||
gifMedia.LoadedBehavior = MediaState.Play;
|
||||
gifMedia.Source = new Uri(item.Key);
|
||||
_ = LoadedSprites.Children.Add(gifMedia);
|
||||
*/
|
||||
Image spriteImage = new();
|
||||
RBG.Helpers.AnimatedBitmapImage animatedBitmap = new(new MemoryStream(item.Value), spriteImage, Application.Current.Dispatcher);
|
||||
_ = LoadedSprites.Children.Add(spriteImage);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// On failed, use the cached data
|
||||
BitmapImage image = new();
|
||||
image.BeginInit();
|
||||
image.StreamSource = new MemoryStream(item.Value);
|
||||
image.EndInit();
|
||||
Image spriteImage = new()
|
||||
{
|
||||
Source = image
|
||||
};
|
||||
_ = LoadedSprites.Children.Add(spriteImage);
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
BitmapImage image = new();
|
||||
image.BeginInit();
|
||||
image.StreamSource = new MemoryStream(item.Value);
|
||||
image.EndInit();
|
||||
Image spriteImage = new()
|
||||
{
|
||||
Source = image
|
||||
};
|
||||
_ = LoadedSprites.Children.Add(spriteImage);
|
||||
}
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
@ -1,6 +1,12 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Threading;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RBG.Helpers
|
||||
{
|
||||
@ -83,4 +89,47 @@ namespace RBG.Helpers
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class AnimatedBitmapImage
|
||||
{
|
||||
public BitmapSource BaseImage { get; set; }
|
||||
BitmapFrame[] frames;
|
||||
int framerate;
|
||||
int currentFrame;
|
||||
Timer frameChange;
|
||||
public AnimatedBitmapImage(Stream source, Image target, Dispatcher dispatcher)
|
||||
{
|
||||
GifBitmapDecoder decoder = new(source, BitmapCreateOptions.None, BitmapCacheOption.Default);
|
||||
frames = new BitmapFrame[decoder.Frames.Count];
|
||||
decoder.Frames.CopyTo(frames, 0);
|
||||
|
||||
byte[] frameratebytes = new byte[2];
|
||||
source.Position = 0x324;
|
||||
frameratebytes[0] = (byte)source.ReadByte();
|
||||
frameratebytes[1] = (byte)source.ReadByte();
|
||||
framerate = 33;
|
||||
|
||||
BaseImage = frames[0];
|
||||
// cycle through frames
|
||||
frameChange = new Timer((t) =>
|
||||
{
|
||||
currentFrame++;
|
||||
currentFrame %= frames.Length;
|
||||
BaseImage = frames[currentFrame];
|
||||
_ = dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Render, new Action(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
target.Source = BaseImage;
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}));
|
||||
},null, framerate, framerate);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net5.0-windows10.0.19041.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
|
@ -4,6 +4,8 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace RBG_Server
|
||||
{
|
||||
@ -11,8 +13,18 @@ namespace RBG_Server
|
||||
/// Data class containing information about a player. Drawn directly to the screen, hence the inheritance
|
||||
/// of Image, which allows this entire object to be
|
||||
/// </summary>
|
||||
public class Player : Image
|
||||
public class Player : Grid
|
||||
{
|
||||
static GradientStopCollection gradientStops = new(5)
|
||||
{
|
||||
new GradientStop(Color.FromArgb(255, 0, 255, 255), 0),
|
||||
new GradientStop(Color.FromArgb(192, 0, 255, 255), 0.75),
|
||||
new GradientStop(Color.FromArgb(128, 0, 255, 255), 0.85),
|
||||
new GradientStop(Color.FromArgb(32, 0, 255, 255), 0.95),
|
||||
new GradientStop(Color.FromArgb(0, 0, 255, 255), 1)
|
||||
};
|
||||
static RadialGradientBrush shadowBrush = new(gradientStops);
|
||||
|
||||
// C# uses implicit field definitions; i.e. declaring a property creates an implicit private field
|
||||
// Note that it is also possible to assign values, and specify access modifiers for the get & set independantly
|
||||
public string PlayerName { get; set; }
|
||||
@ -21,6 +33,10 @@ namespace RBG_Server
|
||||
public long LastTime { get; set; } = DateTime.Now.Ticks;
|
||||
public bool Connected { get; private set; }
|
||||
public byte[] UnhandledBuffer { get; set; }
|
||||
|
||||
public Image PlayerSprite { get; set; } = new();
|
||||
private Rectangle spriteShadow = new();
|
||||
|
||||
private int processing;
|
||||
|
||||
public int ObtainLock()
|
||||
@ -43,6 +59,10 @@ namespace RBG_Server
|
||||
LastTime = DateTime.Now.Ticks;
|
||||
Connected = true;
|
||||
UnhandledBuffer = Array.Empty<byte>();
|
||||
|
||||
spriteShadow.Fill = shadowBrush;
|
||||
Children.Add(spriteShadow);
|
||||
Children.Add(PlayerSprite);
|
||||
}
|
||||
|
||||
public new bool Equals(object obj)
|
||||
|
Loading…
x
Reference in New Issue
Block a user