Jak najprościej zrobić, aby przezroczysty obrazek płynie poruszał się od jednej komórki kontrolki Grid (WPF) do sąsiedniej?
Mój XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Wumpus.MainWindow"
x:Name="Window"
Title="Wumpus World"
WindowState="Maximized">
<StackPanel>
<WrapPanel>
<!--<Image Source="gfx/Player.gif" Width="65" Panel.ZIndex="100" Margin="100,0,0,0" />-->
<Border Panel.ZIndex="0" BorderBrush="Black" BorderThickness="3" Width="503" Height="503">
<Grid Panel.ZIndex="0" Width="500" Height="500" ShowGridLines="true" Name="WGrid">
</Grid>
</Border>
<ListBox Name="PredykatyList" Width="Auto" Height="500">
</ListBox>
</WrapPanel>
<Label Height="Auto">
<WrapPanel>
<TextBlock Name="ScoreTextBlock" TextWrapping="Wrap"></TextBlock>
<TextBlock Name="TimeTextBlock" TextWrapping="Wrap"></TextBlock>
</WrapPanel>
</Label>
<WrapPanel>
<Button Content="Następny krok" Height="23" Name="StepButton" Width="175" Margin="20" Click="StepButton_Click" />
<Button Content="Wykonaj 100 rundek" Height="23" Name="RoundButton" Width="175" Click="RoundButton_Click" />
</WrapPanel>
</StackPanel>
</Window>
Code-behind (C#):
(...)
namespace Wumpus
{
public partial class MainWindow : Window
{
private uint _size = 7;
private BitmapImage _wumpus = null;
private BitmapImage _pit = null;
private BitmapImage _player = null;
private BitmapImage _wall = null;
private BitmapImage _gold = null;
private BitmapImage EastPlayer, SouthPlayer, WestPlayer, NorthPlayer;
private game.level _lvl = null;
private double imageHeight = 0;
private double imageWidth = 0;
public Image[,] _imgGrid = null;
private BazaWiedzy bw = new BazaWiedzy();
private bool alive = true;
private bool win = false;
private int time = 1;
private int return_timer = 0;
private int Score = 0;
public MainWindow()
{
this.InitializeComponent();
_imgGrid = new Image[_size,_size];
imageWidth = WGrid.Width / _size * 0.9;
imageHeight = WGrid.Height / _size * 0.9;
for (int i = 0; i < _size; i++)
{
ColumnDefinition col = new ColumnDefinition();
col.Width = new GridLength(WGrid.Width / _size);
WGrid.ColumnDefinitions.Add(col);
RowDefinition row = new RowDefinition();
row.Height = new GridLength(WGrid.Height / _size);
WGrid.RowDefinitions.Add(row);
}
initRes();
RedrawWorld();
}
private void initRes()
{
_wumpus = new BitmapImage(new Uri("gfx/Wumpus.gif", UriKind.RelativeOrAbsolute));
_gold = new BitmapImage(new Uri("gfx/Gold.gif", UriKind.RelativeOrAbsolute));
_pit = new BitmapImage(new Uri("gfx/Pit.gif", UriKind.RelativeOrAbsolute));
_player = new BitmapImage(new Uri("gfx/Player.gif", UriKind.RelativeOrAbsolute));
_wall = new BitmapImage(new Uri("gfx/Wall.gif", UriKind.RelativeOrAbsolute));
EastPlayer = new BitmapImage(new Uri("gfx/EastPlayer.gif", UriKind.RelativeOrAbsolute));
WestPlayer = new BitmapImage(new Uri("gfx/WestPlayer.gif", UriKind.RelativeOrAbsolute));
SouthPlayer = new BitmapImage(new Uri("gfx/SouthPlayer.gif", UriKind.RelativeOrAbsolute));
NorthPlayer = new BitmapImage(new Uri("gfx/NorthPlayer.gif", UriKind.RelativeOrAbsolute));
for (uint x = 0; x < _size; ++x)
for (uint y = 0; y < _size; ++y)
{
_imgGrid[x,y] = new Image();
_imgGrid[x, y].Height = imageHeight;
_imgGrid[x, y].Width = imageWidth;
WGrid.Children.Add(_imgGrid[x, y]);
Grid.SetRow(_imgGrid[x, y], (int)y);
Grid.SetColumn(_imgGrid[x, y], (int)x);
}
_lvl = new game.level(_size);
_lvl.clearMap();
_lvl.onNewEnviroment += newEnviroment;
_lvl.onWallHit += wallHit;
fillKB();
}
(...)
private void setBitmap(BitmapImage bi, uint x, uint y)
{
if (x >= _size || y >= _size)
return;
_imgGrid[x, y].Source = bi;
_imgGrid[x, y] = new Image();
_imgGrid[x, y].Height = imageHeight;
_imgGrid[x, y].Width = imageWidth;
WGrid.Children.Add(_imgGrid[x, y]);
Grid.SetRow(_imgGrid[x, y], (int)y);
Grid.SetColumn(_imgGrid[x, y], (int)x);
}
public void RedrawWorld()
{
WGrid.Children.Clear();
for(uint x = 0; x < _size; ++x)
for (uint y = 0; y < _size; ++y)
{
setBitmap(null, x, y);
if (_lvl.map[x, y].wumpus)
setBitmap(_wumpus, x, y);
else if (_lvl.map[x, y].gold)
setBitmap(_gold, x, y);
else if (_lvl.map[x, y].pit)
setBitmap(_pit, x, y);
else if (_lvl.map[x, y].wall)
setBitmap(_wall, x, y);
}
switch (_lvl.afterWallHit)
{
case Wumpus.game.level.AfterWallHit.no:
setBitmap(_player, _lvl.player_x, _lvl.player_y);
break;
case Wumpus.game.level.AfterWallHit.EAST:
setBitmap(EastPlayer, _lvl.player_x, _lvl.player_y);
break;
case Wumpus.game.level.AfterWallHit.WEST:
setBitmap(WestPlayer, _lvl.player_x, _lvl.player_y);
break;
case Wumpus.game.level.AfterWallHit.NORTH:
setBitmap(NorthPlayer, _lvl.player_x, _lvl.player_y);
break;
case Wumpus.game.level.AfterWallHit.SOUTH:
setBitmap(SouthPlayer, _lvl.player_x, _lvl.player_y);
break;
}
}
public void RefreshList()
{
PredykatyList.Items.Clear();
foreach (Formula f in bw.Formuly)
{
PredykatyList.Items.Add(f.ToString());
}
}
(...)
public bool TakeStep()
{
//Ask
List<Podstawienie> akcja = bw.Ask(new Predykat("Najlepsza", new string[] { "\""+time.ToString()+"\"", "akcja" }, false));
if(akcja.Count == 0)
akcja = bw.Ask(new Predykat("Dobra", new string[] { "\"" + time.ToString() + "\"", "akcja" }, false));
if (akcja.Count == 0)
akcja = bw.Ask(new Predykat("Ryzykowna", new string[] { "\"" + time.ToString() + "\"", "akcja" }, false));
if (akcja.Count == 0)
akcja = bw.Ask(new Predykat("Samobójcza", new string[] { "\"" + time.ToString() + "\"", "akcja" }, false));
if (akcja.Count == 0)
{
alive = false;
return false;
}
++time;
//zrób
string do_zrobienia = "";
foreach (Podstawienie p in akcja)
{
do_zrobienia = akcja[0]["akcja"].Substring(1, p["akcja"].Length - 2);
switch (do_zrobienia)
{
case "PodnieśZłoto":
_lvl.pickGold();
break;
case "IdźWsch":
_lvl.moveplayer(Wumpus.game.Direction.EAST);
return_timer = -1;
break;
case "IdźPłd":
_lvl.moveplayer(Wumpus.game.Direction.SOUTH);
return_timer = -1;
break;
case "IdźZach":
_lvl.moveplayer(Wumpus.game.Direction.WEST);
return_timer = -1;
break;
case "IdźPłn":
_lvl.moveplayer(Wumpus.game.Direction.NORTH);
return_timer = -1;
break;
case "Wróć":
//zawracanie
if (return_timer < 0)
return_timer = time;
--return_timer;
List<Podstawienie> powrot = bw.Ask(new Predykat("Jest", new string[] { "posx", "posy", "\"" + return_timer.ToString() + "\"" }, false));
if (powrot.Count == 0)
alive = false;
else
{
foreach (Podstawienie pos in powrot)
{
try
{
int posx = int.Parse(pos["posx"].Substring(1, pos["posx"].Length - 2));
int posy = int.Parse(pos["posy"].Substring(1, pos["posy"].Length - 2));
if (posy == _lvl.player_y)
{
if (posx - _lvl.player_x == 1)
_lvl.moveplayer(Wumpus.game.Direction.EAST);
else if (posx - _lvl.player_x == -1)
_lvl.moveplayer(Wumpus.game.Direction.WEST);
else if (posx == _lvl.player_x)
break;
else
continue;
break;
}
if (posx == _lvl.player_x)
{
if (posy - _lvl.player_y == 1)
_lvl.moveplayer(Wumpus.game.Direction.SOUTH);
else if (posy - _lvl.player_y == -1)
_lvl.moveplayer(Wumpus.game.Direction.NORTH);
else
continue;
break;
}
}
catch
{
alive = false;
}
}
}
//idź tam gdzie był w return_timer
break;
}
break;
}
Score--;
ScoreTextBlock.Text = Score + " pkt ";
RedrawWorld();
if (_lvl.player_x == 0 && _lvl.player_y == 0 && _lvl.hasGold)
{
win = true;
Score += 1000;
ScoreTextBlock.Text = Score + " pkt ";
return false;
}
if (!alive)
{
Score -= 1000;
ScoreTextBlock.Text = Score + " pkt ";
return false;
}
return true;
}
private void StepButton_Click(object sender, RoutedEventArgs e)
{
if (!TakeStep())
{
if (win)
{
MessageBox.Show("Wygrana w " + time.ToString() + " ruchach!");
}
else
{
MessageBox.Show("Agent nieżyje.");
}
bw = new BazaWiedzy();
fillKB();
_lvl.clearMap();
_lvl.generateLevel(1, 2, 6, 1);
win = false;
alive = true;
Score = 0;
time = 1;
RefreshList();
RedrawWorld();
}
}
private void RoundButton_Click(object sender, RoutedEventArgs e)
{
DateTime startTime = DateTime.Now;
for(int i = 0; i < 100; ++i)
{
if(!TakeStep())
{
if (win)
{
MessageBox.Show("Wygrana w " + time.ToString() + " ruchach!");
}
else
{
MessageBox.Show("Agent nieżyje.");
}
bw = new BazaWiedzy();
fillKB();
_lvl.clearMap();
_lvl.generateLevel(1, 2, 6, 1);
win = false;
alive = true;
Score = 0;
time = 1;
RefreshList();
RedrawWorld();
break;
}
if (win)
{
//hurray
ScoreTextBlock.Text = ScoreTextBlock.Text + "(zwycięstwo) ";
}
else
{
//boo hoo
ScoreTextBlock.Text = ScoreTextBlock.Text + "(śmierć) ";
}
bw = new BazaWiedzy();
alive = true;
win = false;
time = 1;
return_timer = 0;
Score = 0;
ScoreTextBlock.Text = "0";
initRes();
RedrawWorld();
}
DateTime stopTime = DateTime.Now;
TimeSpan roznica = stopTime - startTime;
TimeTextBlock.Text = roznica.TotalMilliseconds.ToString() + " ms";
}
}
}
Kontrolka Image wstawiona do WrapPanel zawsze przesuwa kontrolkę Border i Grid nawet, gdy ustawi się im inne atrybuty "Panel.ZIndex". Ustawienie zaś zbyt dużego marginesu kontrolce Image wstawionej w komórce Grid powoduje, że wszystkie obrazki w Grid znikają.
Jak zrobić animację poruszania się przezroczystego obrazka z jednej komórki Grid do sąsiedniej (np. z komórki pierwszej z góry i z lewej strony do sąsiedniej po prawej stronie)? Przezroczysty w sensie, że piksele przezroczystości w PNG nie zasłaniają tego co pod spodem, ale to pewnie da się to zrobić za pomocą atrybutu Opacity. Obrazek gracza, o którym piszę, miałby być przesuwany po naciśnięciu przycisku i na podstawie odpowiedniej zmiennej string. Teraz jest usuwany i wstawiany w inne miejsce tak jak inne obrazki.