feat: smooth snake animation + beautiful Avalonia UI overhaul
- Two-timer architecture: game timer + 60fps render timer for smooth interpolation - Snake body: StreamGeometry path with teal gradient, rounded joins - Directional head with white eyes and dark pupils - Food: pulsating glow, highlight, green leaf animation - Modern dark theme (#0D1117), glassmorphism HUD - Speed indicator bar, score +N popup - High score persistence to JSON - All keyboard shortcuts: Arrows, WASD, Space/P pause, Enter start, R restart, Esc quit - Window resizable, 640x540 default New files: AnimationHelper.cs, HighScoreManager.cs, SnakeRenderer.cs
This commit is contained in:
@@ -1,30 +1,175 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:views="using:Snake.Avalonia.Views"
|
||||
x:Class="Snake.Avalonia.Views.GameView"
|
||||
Background="#0D1117"
|
||||
Focusable="True">
|
||||
<Grid RowDefinitions="Auto,*,Auto" Margin="12">
|
||||
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,8">
|
||||
<TextBlock x:Name="ScoreText" FontSize="16" />
|
||||
<TextBlock x:Name="LevelText" FontSize="16" Margin="24,0,0,0" />
|
||||
<TextBlock x:Name="StatusText" FontSize="16" Margin="24,0,0,0" />
|
||||
</StackPanel>
|
||||
|
||||
<Border Grid.Row="1"
|
||||
BorderBrush="#666"
|
||||
BorderThickness="1"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center">
|
||||
<Canvas x:Name="GameCanvas"
|
||||
Background="#1a1a1a"
|
||||
Focusable="True" />
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
|
||||
<!-- HUD Panel — glassmorphism top bar -->
|
||||
<Border Grid.Row="0"
|
||||
Background="#141C24"
|
||||
BorderBrush="#1E3A3A"
|
||||
BorderThickness="0,0,0,1"
|
||||
Padding="16,10">
|
||||
|
||||
<Grid ColumnDefinitions="Auto,*,Auto,Auto,Auto">
|
||||
|
||||
<!-- Score -->
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal" Spacing="6">
|
||||
<TextBlock Text="🍎" FontSize="16" VerticalAlignment="Center" />
|
||||
<TextBlock x:Name="ScoreText"
|
||||
FontSize="16"
|
||||
FontWeight="Bold"
|
||||
Foreground="#E6EDF3" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Spacer -->
|
||||
<TextBlock Grid.Column="1" />
|
||||
|
||||
<!-- Level -->
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal" Spacing="6" Margin="0,0,24,0">
|
||||
<TextBlock Text="⚡" FontSize="14" VerticalAlignment="Center" />
|
||||
<TextBlock x:Name="LevelText"
|
||||
FontSize="14"
|
||||
Foreground="#8B949E"
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Speed indicator bar -->
|
||||
<Border Grid.Column="3"
|
||||
Width="60" Height="16"
|
||||
Background="#1C2128"
|
||||
CornerRadius="8"
|
||||
Margin="0,0,24,0"
|
||||
VerticalAlignment="Center">
|
||||
<Border x:Name="SpeedBar"
|
||||
Background="#0D9488"
|
||||
CornerRadius="8"
|
||||
HorizontalAlignment="Left"
|
||||
Width="15" />
|
||||
</Border>
|
||||
|
||||
<!-- High Score -->
|
||||
<StackPanel Grid.Column="4" Orientation="Horizontal" Spacing="6">
|
||||
<TextBlock Text="🏆" FontSize="14" VerticalAlignment="Center" />
|
||||
<TextBlock x:Name="HighScoreText"
|
||||
FontSize="14"
|
||||
Foreground="#FBBF24"
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<StackPanel Grid.Row="2"
|
||||
Orientation="Horizontal"
|
||||
HorizontalAlignment="Center"
|
||||
Margin="0,12,0,0">
|
||||
<Button x:Name="StartButton" Content="Start" Width="100" />
|
||||
<Button x:Name="RestartButton" Content="Restart" Width="100" Margin="12,0,0,0" />
|
||||
</StackPanel>
|
||||
<!-- Game canvas area -->
|
||||
<Grid Grid.Row="1">
|
||||
<!-- Snake renderer control -->
|
||||
<views:SnakeRenderer x:Name="SnakeCanvas"
|
||||
BoardWidth="20"
|
||||
BoardHeight="15"
|
||||
CellSize="28"
|
||||
Width="560"
|
||||
Height="420"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center" />
|
||||
|
||||
<!-- Start screen overlay -->
|
||||
<Border x:Name="StartOverlay"
|
||||
Background="#0D1117"
|
||||
IsVisible="True"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
<StackPanel HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Spacing="16">
|
||||
<TextBlock Text="🐍"
|
||||
FontSize="48"
|
||||
HorizontalAlignment="Center" />
|
||||
<TextBlock Text="SNAKE"
|
||||
FontSize="36"
|
||||
FontWeight="Bold"
|
||||
Foreground="#14B8A6"
|
||||
HorizontalAlignment="Center" />
|
||||
<TextBlock Text="Press ENTER or Arrow Keys to Start"
|
||||
FontSize="16"
|
||||
Foreground="#8B949E"
|
||||
HorizontalAlignment="Center"
|
||||
Margin="0,12,0,0" />
|
||||
<TextBlock Text="WASD / Arrows = Move · Space = Pause · R = Restart · Esc = Quit"
|
||||
FontSize="12"
|
||||
Foreground="#484F58"
|
||||
HorizontalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Pause overlay -->
|
||||
<Border x:Name="PauseOverlay"
|
||||
Background="#800D1117"
|
||||
IsVisible="False"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
<StackPanel HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Spacing="12">
|
||||
<TextBlock Text="⏸"
|
||||
FontSize="48"
|
||||
HorizontalAlignment="Center" />
|
||||
<TextBlock Text="PAUSED"
|
||||
FontSize="28"
|
||||
FontWeight="Bold"
|
||||
Foreground="#8B949E"
|
||||
HorizontalAlignment="Center" />
|
||||
<TextBlock Text="Press Space or P to Resume"
|
||||
FontSize="14"
|
||||
Foreground="#484F58"
|
||||
HorizontalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Game Over overlay -->
|
||||
<Border x:Name="GameOverOverlay"
|
||||
Background="#B30D1117"
|
||||
IsVisible="False"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
<StackPanel HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Spacing="12">
|
||||
<TextBlock Text="💀"
|
||||
FontSize="48"
|
||||
HorizontalAlignment="Center" />
|
||||
<TextBlock Text="GAME OVER"
|
||||
FontSize="32"
|
||||
FontWeight="Bold"
|
||||
Foreground="#EF4444"
|
||||
HorizontalAlignment="Center" />
|
||||
<TextBlock x:Name="GameOverScoreText"
|
||||
FontSize="18"
|
||||
Foreground="#E6EDF3"
|
||||
HorizontalAlignment="Center" />
|
||||
<TextBlock x:Name="GameOverHighScoreText"
|
||||
FontSize="14"
|
||||
Foreground="#FBBF24"
|
||||
HorizontalAlignment="Center" />
|
||||
|
||||
<StackPanel Orientation="Horizontal"
|
||||
HorizontalAlignment="Center"
|
||||
Spacing="16"
|
||||
Margin="0,16,0,0">
|
||||
<Button x:Name="GameOverRestartBtn"
|
||||
Content="🔄 Restart"
|
||||
Classes="GameButton"
|
||||
Width="140" />
|
||||
<Button x:Name="GameOverQuitBtn"
|
||||
Content="✕ Quit"
|
||||
Classes="GameButton GameButtonSecondary"
|
||||
Width="140" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Score popup (will be rendered by SnakeRenderer) -->
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
Reference in New Issue
Block a user