Lipiec 2025 r.
Wakacyjne Warsztaty Programowania –
ZS nr 1 w Działdowie
W ramach letniej propozycji edukacyjnej dla uczniów klas 7–8 szkół podstawowych organizujemy Wakacyjne Warsztaty Programowania, których głównym celem jest nauka podstaw języka C# poprzez praktyczne tworzenie prostej gry komputerowej.
Etap 1 – Wprowadzenie do Visual Studio, WPF i przygotowanie projektu gry „JajkaWilk”
👶 Na początek – Co to wszystko znaczy?
Visual Studio 2022
To specjalny program (tzw. środowisko programistyczne), w którym tworzy się aplikacje, gry i strony internetowe.
Można w nim:
- pisać kod,
- projektować okna,
- testować aplikacje.
👉 To jak warsztat dla programisty – wszystko w jednym miejscu.
C# (C-Sharp)
To język programowania, czyli sposób, w jaki mówimy komputerowi, co ma robić.
👨💻 Przykład:
int liczba = 5;
To znaczy: „utwórz zmienną o nazwie liczba i przypisz jej wartość 5”.
C# jest prosty, nowoczesny i często używany do:
- gier,
- aplikacji okienkowych,
- stron internetowych.
WPF
WPF = Windows Presentation Foundation. To technologia do tworzenia ładnych okienkowych aplikacji na Windowsa – takich jak kalkulatory, gry, formularze.
👉 Dzięki WPF robimy:
- interfejs (czyli wygląd okna),
- obsługę kliknięć, klawiszy, dźwięków itp.
XAML
To specjalny język do opisywania, jak ma wyglądać okno aplikacji. To jak HTML, ale dla aplikacji na Windows.
👀 Przykład:
<Button Content="Kliknij mnie" Width="100" Height="30"/>
To przycisk z napisem „Kliknij mnie”.
🪜 Krok po kroku: Tworzenie projektu i wczytanie grafik
Krok 1: Utwórz nowy projekt
- Uruchom Visual Studio 2022.
- Kliknij Utwórz nowy projekt.
- Wyszukaj: WPF i wybierz: ✅ Aplikacja WPF (.NET Framework)
- Kliknij Dalej.
- Wpisz nazwę projektu: JajkaWilk.
- Kliknij Utwórz.
Krok 2: Dodaj folder – Assets
- W oknie Eksplorator rozwiązań (Solution Explorer) po prawej stronie:
- Kliknij prawym przyciskiem myszy na nazwę projektu JajkaWilk.
- Wybierz Dodaj → Nowy folder.
- Nazwij go Assets (to będzie miejsce na grafiki do gry).
Krok 3: Dodaj pliki graficzne do folderu – Assets
- Kliknij prawym przyciskiem na folder Assets.
- Wybierz Dodaj → Istniejący element…
- Wybierz pliki (od nauczyciela), np.:
- tlogry.png (tło gry)
- egg1.png (jajko)
- wilkdol1.png, wilkgora1.png (grafiki wilka)
- Kliknij Dodaj.
Krok 4: Ustaw właściwości każdego pliku graficznego
- Kliknij jeden raz na grafikę (np. egg1.png).
- W oknie Właściwości (na dole lub z prawej – jeśli go nie widać, naciśnij F4):
- Akcja kompilacji → ustaw na: Zawartość
- Kopiuj do katalogu wyjściowego → ustaw na: Zawsze kopiuj
🔁 Powtórz to dla każdej grafiki.
GRATULACJE! Właśnie utworzyłeś swoj projekt w Visual Studio 2022. Gotowy na etap2?
Etap 2 – wersja z Projektantem i Przybornikiem (Toolbox)
Będziemy teraz zbudować planszę gry bez pisania XAML, używając projektanta wizualnego i ustawiając właściwości kontrolek.
🪜 Krok po kroku – Budowa planszy gry z Toolboxa
Krok 1: Otwórz
MainWindow.xaml
- W Eksploratorze rozwiązań kliknij dwukrotnie MainWindow.xaml.
- Pojawi się okno z zakładką Projektant (góra) i XAML (dół).
👁 Jeśli nie widać projektu wizualnego – kliknij „Widok → Projektant” lub skrót Shift + F7.
Krok 2: Zamień domyślny Grid na Canvas
- Kliknij raz na puste pole projektu.
- W oknie Właściwości (z prawej) znajdź pole Typ kontenera.
- Jeśli to możliwe, wybierz Canvas – jeśli nie: 👉 Przejdź do kodu XAML i ręcznie zamień <Grid> na <Canvas Name=”Plansza”>.
Krok 3: Ustaw tło planszy
- Kliknij raz na Canvas (czyli tło).
- W oknie Właściwości znajdź opcję Background.
- Kliknij ikonę „…” obok.
- Wybierz Brush → ImageBrush
- Kliknij „…” przy ImageSource, wybierz Assets/tlogry.png.
📌 Obraz musi mieć ustawione wcześniej:
- Akcja kompilacji: Zawartość
- Kopiuj do katalogu wyjściowego: Zawsze kopiuj
Krok 4: Dodaj TextBlock z punktami
- Otwórz Toolbox (jeśli nie widać: Ctrl + Alt + X lub menu „Widok → Przybornik”).
- Przeciągnij TextBlock na pole gry.
- Kliknij na niego raz i ustaw w Właściwościach:
- Name: LicznikPunktow
- Text: Punkty: 0
- FontSize: 24
- FontWeight: Bold
- Foreground: Biały
- Canvas.Left: 10
- Canvas.Top: 10
Krok 5: Dodaj TextBlock z życiami
- Przeciągnij drugi TextBlock.
- Ustaw:
- Name: LicznikZyc
- Text: Życia: 5
- FontSize: 24
- FontWeight: Bold
- Foreground: #FFFA7C7C
- Canvas.Left: 200
- Canvas.Top: 10
Krok 6: Dodaj Image – wilk
- Przeciągnij z przybornika Image.
- Ustaw:
- Name: Wilk
- Width: 218
- Height: 300
- Source: kliknij „…” → wybierz Assets/wilkdol1.png
- Canvas.Left: 246
- Canvas.Top: 326
Krok 7: Dodaj Border – koszyk
- Przeciągnij Border z Toolboxa.
- Ustaw:
- Name: Koszyk
- Width: 40
- Height: 40
- Opacity: 0.5
- Background: Gray
- Canvas.Left: 274
- Canvas.Top: 452
Efekt końcowy:
Po kliknięciu Uruchom bez debugowania (Ctrl + F5) zobaczysz:
szary koszyk (który będzie odpowiadał za łapanie jajek).
pełne tło gry,
licznik punktów i żyć,
wilka na dole,
Twój kod xaml powinien wyglądać teraz tak.
<Window x:Class="JajkaWIlk.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="JajkaWilk" Height="750" Width="750"
WindowStartupLocation="CenterScreen"
ResizeMode="NoResize"
SizeToContent="Manual"
KeyDown="Window_KeyDown"
KeyUp="Window_KeyUp">
<Canvas Name="Plansza">
<!-- Tło -->
<Canvas.Background>
<ImageBrush ImageSource="pack://application:,,,/Assets/tlogry.png" Stretch="Fill"/>
</Canvas.Background>
<!-- Punkty -->
<TextBlock x:Name="LicznikPunktow"
FontSize="24"
FontWeight="Bold"
Foreground="White"
Canvas.Left="10"
Canvas.Top="10"
Text="Punkty: 0"/>
<!-- Życia -->
<TextBlock x:Name="LicznikZyc"
FontSize="24"
FontWeight="Bold"
Foreground="#FFFA7C7C"
Canvas.Left="200"
Canvas.Top="10"
Text="Życia: 5"/>
<!-- Koszyk (obszar kolizji) -->
<Border x:Name="Koszyk"
Width="40"
Height="40"
Opacity="0.5"
Canvas.Left="274"
Canvas.Top="452"/>
<!-- Wilk -->
<Image Name="Wilk"
Width="218" Height="300"
Source="pack://application:,,,/Assets/wilkdol1.png"
Canvas.Left="246"
Canvas.Top="326"
HorizontalAlignment="Left"
VerticalAlignment="Top"/>
</Canvas>
</Window>
Jeśli wszystko przebiegło pomyślnie, to właśnie stworzyłeś swoją pierwszą planszę w C# do gry. Gotowy na kolejny etap?
Etap3: Tworzenie logiki gry w pliku MainWindow.xaml.cs
W tym etapie zajmiemy się napisaniem kodu, który będzie obsługiwał całą logikę gry „Jajka Wilk”. Będziemy krok po kroku analizować i dodawać odpowiednie fragmenty kodu do pliku MainWindow.xaml.cs, wyjaśniając, co robi każda linia.
Krok 1: Import potrzebnych bibliotek
Na samej górze pliku dodajemy biblioteki, które umożliwią nam:
- tworzenie elementów graficznych (Image, Canvas itp.),
- obsługę zdarzeń (klawiatura),
- tworzenie timerów do spadających jajek,
- losowanie pozycji.
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using System.Collections.Generic;
Krok 2: Deklaracja klasy głównej i elementów gry
Teraz zaczynamy pisać klasę MainWindow, która dziedziczy po klasie Window. W niej będą wszystkie nasze pola, metody i logika gry.
namespace JajkaWIlk
{
public partial class MainWindow : Window
{
Krok 3: Definiujemy typy pomocnicze – enum i struct
Chcemy mieć uporządkowane informacje o pozycjach wilka oraz o jajkach, dlatego tworzymy:
enum Pozycja– typ wyliczeniowy, który przechowuje możliwe pozycje wilka i jajek,struct JajkoData– struktura przechowująca informacje o jednym jajku: jego grafikę i pozycję początkową.
private enum Pozycja { LewaGora, LewyDol, PrawaGora, PrawyDol } // Pozycje grządek i wilka
private struct JajkoData
{
public Image Obraz; // obraz jajka
public Pozycja PozycjaStartowa; // z której grządki spada
}
Krok 4: Pola klasy – zmienne przechowujące stan gry
Tworzymy zmienne, które będą potrzebne do działania gry:
- generowanie liczb losowych,
- zegary (timery),
- lista jajek aktualnie spadających,
- licznik punktów i żyć,
- flagi dla wciśnięcia klawiszy,
- aktualna pozycja wilka,
- współrzędne startowe jajek (dopasowane do tła).
private Random los = new Random();
private DispatcherTimer timerNoweJajko = new DispatcherTimer();
private DispatcherTimer timerRuchJajek = new DispatcherTimer();
private List<JajkoData> aktywneJajka = new List<JajkoData>();
private int punkty = 0;
private int zycia = 5;
private bool lewoWcisniete = false;
private bool prawoWcisniete = false;
private bool goraWcisnieta = false;
private bool dolWcisniete = false;
private Pozycja aktualnaPozycjaWilka = Pozycja.LewyDol;
private readonly Point startLG = new Point(150, 140);
private readonly Point startLD = new Point(100, 300);
private readonly Point startPG = new Point(550, 135);
private readonly Point startPD = new Point(550, 315);
Krok 5: Konstruktor – co ma się uruchomić na początku
Metoda MainWindow() to tzw. konstruktor. Jest wykonywana automatycznie po uruchomieniu gry. Dodajemy w niej:
- inicjalizację komponentów (czyli załadowanie XAML-a),
- podpięcie obsługi klawiszy (KeyDown, KeyUp),
- konfigurację timerów do jajek (interwał i start),
- inicjalizację liczników punktów i żyć.
public MainWindow()
{
InitializeComponent(); // ładowanie wyglądu z XAML
// obsługa klawiatury
this.KeyDown += Window_KeyDown;
this.KeyUp += Window_KeyUp;
// start timera od jajek
timerNoweJajko.Interval = TimeSpan.FromSeconds(los.Next(2, 5));
timerNoweJajko.Tick += TimerNoweJajko_Tick;
timerNoweJajko.Start();
// start timera od ruchu jajek
timerRuchJajek.Interval = TimeSpan.FromMilliseconds(70);
timerRuchJajek.Tick += TimerRuchJajek_Tick;
timerRuchJajek.Start();
AktualizujPunkty(); // licznik punktów
AktualizujZycia(); // licznik żyć
}
Krok 6: Tworzenie nowych jajek
Timer timerNoweJajko wywołuje co kilka sekund metodę TimerNoweJajko_Tick, która tworzy nowe jajko w losowym miejscu.
private void TimerNoweJajko_Tick(object? sender, EventArgs e)
{
DodajNoweJajko(); // dodaj nowe jajko do gry
timerNoweJajko.Interval = TimeSpan.FromSeconds(los.Next(2, 5)); // ustaw kolejny czas
}
Metoda DodajNoweJajko() ustala pozycję startową, tworzy obrazek jajka i dodaje go do planszy i listy.
private void DodajNoweJajko()
{
int wybor = los.Next(4); // losuj jedną z czterech pozycji
Pozycja pozycja = (Pozycja)wybor; // przekształć na wartość typu Pozycja
Point start = pozycja switch
{
Pozycja.LewaGora => startLG,
Pozycja.LewyDol => startLD,
Pozycja.PrawaGora => startPG,
Pozycja.PrawyDol => startPD,
_ => startLG
};
Image jajko = new Image
{
Width = 50,
Height = 50,
Source = new BitmapImage(new Uri("pack://application:,,,/Assets/egg1.png")) // grafika jajka
};
Canvas.SetLeft(jajko, start.X); // pozycja na planszy X
Canvas.SetTop(jajko, start.Y); // pozycja na planszy Y
Plansza.Children.Add(jajko); // dodaj do planszy
aktywneJajka.Add(new JajkoData { Obraz = jajko, PozycjaStartowa = pozycja }); // zapisz do listy
}
Krok 7: Poruszanie jajkami i wykrywanie kolizji
W tej części gry zajmujemy się ruchem wszystkich jajek na planszy. Timer timerRuchJajek uruchamia się co 70 ms i przesuwa każde jajko w odpowiednim kierunku. Dodatkowo sprawdza, czy jajko:
- zostało złapane przez gracza (kolizja z koszykiem),
- spadło poza planszę (utrata życia).
To najważniejsza metoda logiki gry, odpowiadająca za obsługę całej mechaniki łapania i tracenia jajek.
private void TimerRuchJajek_Tick(object? sender, EventArgs e)
{
List<JajkoData> doUsuniecia = new List<JajkoData>(); // lista jajek do usunięcia
foreach (var jajkoData in aktywneJajka)
{
double x = Canvas.GetLeft(jajkoData.Obraz);
double y = Canvas.GetTop(jajkoData.Obraz);
// Ruch jajek zależny od pozycji startowej (trajektoria)
switch (jajkoData.PozycjaStartowa)
{
case Pozycja.LewaGora: x += 3.5; y += 1.6; break;
case Pozycja.LewyDol: x += 3.5; y += 1.9; break;
case Pozycja.PrawaGora: x -= 3.5; y += 1.7; break;
case Pozycja.PrawyDol: x -= 3.5; y += 1.9; break;
}
// Ustawiamy nową pozycję jajka
Canvas.SetLeft(jajkoData.Obraz, x);
Canvas.SetTop(jajkoData.Obraz, y);
// Tworzymy prostokąty do sprawdzenia kolizji (jajko i koszyk)
Rect jajkoRect = new Rect(x, y, jajkoData.Obraz.Width, jajkoData.Obraz.Height);
Rect koszykRect = new Rect(Canvas.GetLeft(Koszyk), Canvas.GetTop(Koszyk), Koszyk.Width, Koszyk.Height);
// Czy jajko zostało złapane?
if (jajkoRect.IntersectsWith(koszykRect) && jajkoData.PozycjaStartowa == aktualnaPozycjaWilka)
{
Plansza.Children.Remove(jajkoData.Obraz); // usuń z planszy
doUsuniecia.Add(jajkoData); // oznacz do usunięcia z listy
punkty++; // dodaj punkt
AktualizujPunkty();
}
else if (y > 700 || x < 0 || x > 700) // Czy jajko spadło poza planszę?
{
Plansza.Children.Remove(jajkoData.Obraz);
doUsuniecia.Add(jajkoData);
zycia--; // tracimy życie
AktualizujZycia();
// Koniec gry, jeśli brak żyć
if (zycia <= 0)
{
timerNoweJajko.Stop();
timerRuchJajek.Stop();
MessageBox.Show("Koniec gry! Twoje punkty: " + punkty);
}
}
}
// Usuń złapane lub rozbite jajka z listy
foreach (var jajko in doUsuniecia)
aktywneJajka.Remove(jajko);
}
Krok 8: Aktualizacja liczników – punkty i życia
Aby gracz wiedział, ile ma punktów i żyć, musimy zaktualizować odpowiednie pola tekstowe na planszy. Zrobimy to w dwóch metodach: AktualizujPunkty() i AktualizujZycia().
Punkty
Wyświetlamy aktualną liczbę punktów w kontrolce LicznikPunktow, która znajduje się na planszy (dodana wcześniej w pliku XAML).
private void AktualizujPunkty()
{
LicznikPunktow.Text = $"Punkty: {punkty}"; // aktualizacja napisu z punktami
}
Życia
Sprawdzamy, czy TextBlock LicznikZyc istnieje. Jeśli tak – aktualizujemy jego tekst. Jeśli nie – tworzymy go na nowo (przy starcie gry).
private void AktualizujZycia()
{
if (Plansza.FindName("LicznikZyc") is TextBlock t)
{
// jeśli licznik istnieje, zmień tylko wartość
t.Text = $"\u2665: {zycia}";
}
else
{
// jeśli nie istnieje – utwórz licznik żyć
TextBlock zyciaBlock = new TextBlock
{
Name = "LicznikZyc",
FontSize = 24,
FontWeight = FontWeights.Bold,
Foreground = Brushes.Red,
Text = $"\u2665: {zycia}"
};
Canvas.SetLeft(zyciaBlock, 650);
Canvas.SetTop(zyciaBlock, 10);
Plansza.Children.Add(zyciaBlock);
RegisterName("LicznikZyc", zyciaBlock); // rejestrujemy nowy TextBlock po imieniu
}
}
Krok 9: Sterowanie klawiaturą – zmiana pozycji wilka
Gracz steruje wilkiem za pomocą klawiszy strzałek: lewo/prawo + góra/dół. Musimy wykryć, które klawisze są aktualnie wciśnięte i odpowiednio ustawić pozycję wilka oraz koszyka.
Wciśnięcie klawisza (KeyDown)
Tutaj ustawiamy flagi (bo możliwe są kombinacje klawiszy) i na ich podstawie ustalamy pozycję wilka oraz koszyka.
private void Window_KeyDown(object sender, KeyEventArgs e)
{
// zapamiętujemy które klawisze są wciśnięte
if (e.Key == Key.Left) lewoWcisniete = true;
if (e.Key == Key.Right) prawoWcisniete = true;
if (e.Key == Key.Up) goraWcisnieta = true;
if (e.Key == Key.Down) dolWcisniete = true;
// kombinacje sterujące wilkiem
if (lewoWcisniete && goraWcisnieta)
{
aktualnaPozycjaWilka = Pozycja.LewaGora;
UstawWilka(240, 180, "Assets/wilkgora1.png", false);
UstawKoszyk(274, 238);
}
else if (lewoWcisniete && dolWcisniete)
{
aktualnaPozycjaWilka = Pozycja.LewyDol;
UstawWilka(240, 330, "Assets/wilkdol1.png", false);
UstawKoszyk(274, 432);
}
else if (prawoWcisniete && goraWcisnieta)
{
aktualnaPozycjaWilka = Pozycja.PrawaGora;
UstawWilka(240, 195, "Assets/wilkgora1.png", true); // prawa strona = obrócenie wilka
UstawKoszyk(385, 228);
}
else if (prawoWcisniete && dolWcisniete)
{
aktualnaPozycjaWilka = Pozycja.PrawyDol;
UstawWilka(240, 330, "Assets/wilkdol1.png", true);
UstawKoszyk(385, 432);
}
e.Handled = true; // zatrzymujemy dalsze przetwarzanie klawisza
}
Zwolnienie klawisza (KeyUp)
Gdy gracz puszcza klawisz, flaga powinna wrócić do wartości false.
private void Window_KeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Left) lewoWcisniete = false;
if (e.Key == Key.Right) prawoWcisniete = false;
if (e.Key == Key.Up) goraWcisnieta = false;
if (e.Key == Key.Down) dolWcisniete = false;
}
Krok 10: Pomocnicze metody do ustawiania wilka i koszyka
Te metody są wywoływane w zależności od pozycji wilka. Dzięki nim możemy:
- zmienić obrazek wilka,
- ustawić go we właściwe miejsce na planszy,
- przesunąć przezroczysty koszyk do odpowiedniej pozycji (służy do sprawdzania kolizji z jajkami).
Ustaw Wilka
private void UstawWilka(double left, double top, string sciezka, bool obrocWPrawo)
{
// ładowanie nowego obrazka wilka
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.UriSource = new Uri($"pack://application:,,,/{sciezka}", UriKind.Absolute);
bitmap.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
bitmap.EndInit();
Wilk.Source = bitmap; // ustawiamy nowy obrazek
Canvas.SetLeft(Wilk, left); // przesuwamy na planszy
Canvas.SetTop(Wilk, top);
// jeśli prawa strona – odbij obrazek w poziomie
Wilk.LayoutTransform = obrocWPrawo ? new ScaleTransform(-1, 1) : null;
}
Ustaw Koszyk
private void UstawKoszyk(double left, double top)
{
// ustawiamy przezroczysty koszyk do kolizji z jajkiem
Canvas.SetLeft(Koszyk, left);
Canvas.SetTop(Koszyk, top);
}
Cały kod dla CS
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using System.Collections.Generic;
namespace JajkaWIlk
{
public partial class MainWindow : Window
{
// ========== ENUM i STRUKTURY ==========
// Pozycje, w których może znajdować się wilk (i z których mogą spadać jajka)
private enum Pozycja { LewaGora, LewyDol, PrawaGora, PrawyDol }
// Dane o jajku: jego obrazek i pozycja startowa
private struct JajkoData
{
public Image Obraz;
public Pozycja PozycjaStartowa;
}
// ========== POLA KLASOWE (czyli zmienne dla całej gry) ==========
private Random los = new Random(); // Losowanie (np. wyboru pozycji jajka)
private DispatcherTimer timerNoweJajko = new DispatcherTimer(); // Zegar do tworzenia nowych jajek
private DispatcherTimer timerRuchJajek = new DispatcherTimer(); // Zegar do poruszania jajkami
private List<JajkoData> aktywneJajka = new List<JajkoData>(); // Lista aktualnie spadających jajek
private int punkty = 0; // Liczba zdobytych punktów
private int zycia = 5; // Liczba pozostałych żyć
// Flagi wciskania klawiszy (pozwalają sprawdzić, które klawisze są aktualnie wciśnięte)
private bool lewoWcisniete = false;
private bool prawoWcisniete = false;
private bool goraWcisnieta = false;
private bool dolWcisniete = false;
// Aktualna pozycja wilka
private Pozycja aktualnaPozycjaWilka = Pozycja.LewyDol;
// Pozycje startowe jajek (dopasowane do grządek na obrazku)
private readonly Point startLG = new Point(150, 140);
private readonly Point startLD = new Point(100, 300);
private readonly Point startPG = new Point(550, 135);
private readonly Point startPD = new Point(550, 315);
// ========== KONSTRUKTOR ==========
public MainWindow()
{
InitializeComponent();
// Obsługa klawiatury
this.KeyDown += Window_KeyDown;
this.KeyUp += Window_KeyUp;
// Start zegara do generowania jajek
timerNoweJajko.Interval = TimeSpan.FromSeconds(los.Next(2, 5)); // Tu można zmienić
prędkość pojawiania się jajek
timerNoweJajko.Tick += TimerNoweJajko_Tick;
timerNoweJajko.Start();
// Start zegara do ruchu jajek
timerRuchJajek.Interval = TimeSpan.FromMilliseconds(70); // Tu można zmienić szybkość
opadania jajek
timerRuchJajek.Tick += TimerRuchJajek_Tick;
timerRuchJajek.Start();
AktualizujPunkty(); // Ustawienie tekstu na starcie
AktualizujZycia(); // Ustawienie liczby żyć na
starcie
}
// ========== TWORZENIE JAJEK ==========
private void TimerNoweJajko_Tick(object? sender, EventArgs e)
{
DodajNoweJajko(); // Dodaje nowe jajko na planszę
timerNoweJajko.Interval = TimeSpan.FromSeconds(los.Next(2, 5)); // Ustala czas do
następnego jajka
}
private void DodajNoweJajko()
{
int wybor = los.Next(4); // Losuje jedną z 4 pozycji
Pozycja pozycja = (Pozycja)wybor;
// Ustala punkt startowy
jajka w zależności od pozycji
Point start = pozycja switch
{
Pozycja.LewaGora => startLG,
Pozycja.LewyDol => startLD,
Pozycja.PrawaGora => startPG,
Pozycja.PrawyDol => startPD,
_ => startLG
};
// Tworzy nowe jajko jako obrazek
Image jajko = new Image
{
Width = 50,
Height = 50,
Source = new BitmapImage(new Uri("pack://application:,,,/Assets/egg1.png")) // Tutaj można
podmienić grafikę jajka
};
// Ustawienie pozycji startowej jajka
Canvas.SetLeft(jajko, start.X);
Canvas.SetTop(jajko, start.Y);
Plansza.Children.Add(jajko);
// Dodanie do listy aktywnych jajek
aktywneJajka.Add(new JajkoData { Obraz = jajko, PozycjaStartowa = pozycja });
}
// ========== RUCH I KOLIZJE JAJEK ==========
private void TimerRuchJajek_Tick(object? sender, EventArgs e)
{
List<JajkoData> doUsuniecia = new List<JajkoData>();
foreach (var jajkoData in aktywneJajka)
{
double x = Canvas.GetLeft(jajkoData.Obraz);
double y = Canvas.GetTop(jajkoData.Obraz);
// Tu można zmieniać trajektorie spadania jajek (zmieniając współczynniki x i y)
switch (jajkoData.PozycjaStartowa)
{
case Pozycja.LewaGora: x += 3.5; y += 1.6; break;
case Pozycja.LewyDol: x += 3.5; y += 1.9; break;
case Pozycja.PrawaGora: x -= 3.5; y += 1.7; break;
case Pozycja.PrawyDol: x -= 3.5; y += 1.9; break;
}
// Ustawienie nowej pozycji jajka
Canvas.SetLeft(jajkoData.Obraz, x);
Canvas.SetTop(jajkoData.Obraz, y);
// Sprawdzenie kolizji jajka z koszykiem
Rect jajkoRect = new Rect(x, y, jajkoData.Obraz.Width, jajkoData.Obraz.Height);
Rect koszykRect = new Rect(Canvas.GetLeft(Koszyk), Canvas.GetTop(Koszyk), Koszyk.Width, Koszyk.Height);
// Jeśli jajko zostało złapane
if (jajkoRect.IntersectsWith(koszykRect) && jajkoData.PozycjaStartowa == aktualnaPozycjaWilka)
{
Plansza.Children.Remove(jajkoData.Obraz);
doUsuniecia.Add(jajkoData);
punkty++;
AktualizujPunkty();
}
// Jeśli jajko spadło poza ekran
else if (y > 700 || x < 0 || x > 700)
{
Plansza.Children.Remove(jajkoData.Obraz);
doUsuniecia.Add(jajkoData);
zycia--;
AktualizujZycia();
// Jeśli gracz przegrał wszystkie życia
if (zycia <= 0)
{
timerNoweJajko.Stop();
timerRuchJajek.Stop();
MessageBox.Show("Koniec gry! Twoje punkty: " + punkty);
}
}
}
// Usunięcie jajek z listy aktywnych
foreach (var jajko in doUsuniecia)
aktywneJajka.Remove(jajko);
}
// ========== AKTUALIZACJA PUNKTÓW I ŻYĆ ==========
private void AktualizujPunkty()
{
LicznikPunktow.Text = $"Punkty: {punkty}";
}
private void AktualizujZycia()
{
if (Plansza.FindName("LicznikZyc") is TextBlock t)
{
t.Text = $"\u2665: {zycia}";
}
else
{
// Jeśli licznik nie istnieje (np. przy starcie),
tworzy go
TextBlock zyciaBlock = new TextBlock
{
Name = "LicznikZyc",
FontSize = 24,
FontWeight = FontWeights.Bold,
Foreground = Brushes.Red,
Text = $"\u2665: {zycia}"
};
Canvas.SetLeft(zyciaBlock, 650);
Canvas.SetTop(zyciaBlock, 10);
Plansza.Children.Add(zyciaBlock);
RegisterName("LicznikZyc", zyciaBlock);
}
}
// ========== OBSŁUGA KLAWISZY (STEROWANIE WILKIEM) ==========
private void Window_KeyDown(object sender, KeyEventArgs e)
{
// Zaznaczamy, które klawisze są wciśnięte
if (e.Key == Key.Left) lewoWcisniete = true;
if (e.Key == Key.Right) prawoWcisniete = true;
if (e.Key == Key.Up) goraWcisnieta = true;
if (e.Key == Key.Down) dolWcisniete = true;
// Kombinacje klawiszy → zmiana pozycji wilka
if (lewoWcisniete && goraWcisnieta)
{
aktualnaPozycjaWilka = Pozycja.LewaGora;
UstawWilka(240, 180, "Assets/wilkgora1.png", false);
UstawKoszyk(274, 238);
}
else if (lewoWcisniete && dolWcisniete)
{
aktualnaPozycjaWilka = Pozycja.LewyDol;
UstawWilka(240, 330, "Assets/wilkdol1.png", false);
UstawKoszyk(274, 432);
}
else if (prawoWcisniete && goraWcisnieta)
{
aktualnaPozycjaWilka = Pozycja.PrawaGora;
UstawWilka(240, 195, "Assets/wilkgora1.png", true);
UstawKoszyk(385, 228);
}
else if (prawoWcisniete && dolWcisniete)
{
aktualnaPozycjaWilka = Pozycja.PrawyDol;
UstawWilka(240, 330, "Assets/wilkdol1.png", true);
UstawKoszyk(385, 432);
}
e.Handled = true; // Zatrzymanie dalszej obsługi
klawisza
}
private void Window_KeyUp(object sender, KeyEventArgs e)
{
// Gdy klawisz został puszczony – flaga wraca na
false
if (e.Key == Key.Left) lewoWcisniete = false;
if (e.Key == Key.Right) prawoWcisniete = false;
if (e.Key == Key.Up) goraWcisnieta = false;
if (e.Key == Key.Down) dolWcisniete = false;
}
// ========== ZMIANA GRAFIKI WILKA I POZYCJI KOSZYKA ==========
private void UstawWilka(double left, double top, string sciezka, bool obrocWPrawo)
{
// Ładuje nową grafikę wilka z pliku
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.UriSource = new Uri($"pack://application:,,,/{sciezka}", UriKind.Absolute);
bitmap.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
bitmap.EndInit();
// Ustawia nowy obrazek i pozycję wilka
Wilk.Source = bitmap;
Canvas.SetLeft(Wilk, left);
Canvas.SetTop(Wilk, top);
// Jeśli obrazek ma być odbity (dla prawej strony)
Wilk.LayoutTransform = obrocWPrawo ? new ScaleTransform(-1, 1) : null;
}
private void UstawKoszyk(double left, double top)
{
// Ustawienie pozycji niewidzialnego koszyka (do kolizji z jajkami)
Canvas.SetLeft(Koszyk, left);
Canvas.SetTop(Koszyk, top);
}
}
}





