Night of the Living Devs 2012 (sukces :) )

by Filip 29. kwietnia 2012 01:24

W nocy z 20 na 21 kwietnia 2012 odbyła się pierwsza edycja zespołowego konkursu programistycznego "Night of the Living Devs", organizowanego przez Microsoft. W evencie brało udział 15 drużyn z grup .NET z całej Polski - w każdej 6 programistów i 2 grafików. Konkurs trwał przez całą noc od 18:00 do 6:00 i przez ten czas każda drużyna z zapałem pisała aplikacje na Windows Phone ;) Na początku dla każdej drużyny wylosowany został temat jednej dużej aplikacji przeznaczonej na całe 12 godzin, a co każde dwie godziny pojawiały się dwa nowe tematy na dwie mniejsze aplikacje. Konkurs przebiegał w miłej atmosferze i pomimo zmęczenia, sympatycznie nam się pracowało. W rezultacie udało nam się zająć pierwsze miejsce przynosząc chwałę naszemu wydziałowi oraz całej Warszawie ;)

 

 

W składzie naszej drużyny dzielnie kodzili: (kolejność ze zdjęcia)

- Patryk Wąsiewicz: Silverlight Master-Speciallist

- Andrzej Skrodzki: Team Leader (HR + PR)

- Michał Kijowski: Graphics Engineer + .NET RegEx Guru

- Alexander Repnikov: Graphics Designer Visionary

- Filip Daca: XNA Head-Developer

- Paweł Nowosad: Silverlight Developer Evangelist

- Piotr Wiśniewski: Silverlight Power Developer

 

Temat na dużą aplikację, jaki został dla nas wylosowany to "Origami". Uznaliśmy, że zrealizujemy go pisząc grę, w której steruje się żabką z origami, która skacząc po kartce papieru zjada muchy i omija latające żurawie. Ja przejąłem obowiązek pisania głównej gry, a reszta zespołu dzielnie zmagała się z nieustannie pojawiającymi się mniejszymi zadaniami. Podczas całego spotkania powstała niezliczona ilość fantastycznych programów :D (między innymi Atlas Grzybów, Węzły Żeglarskie, Wyniki Lotto, Aplikacja Urodzinowa..)

Tags: ,

Kurs tworzenia gier XNA - spotkanie 2

by Filip 7. kwietnia 2012 16:46

 

Ze względu na termin drugiego spotkania, nie chcieliśmy prezentować na nim żadnych nowych metod ani klas - zamiast tego Paweł poopowiadał o konferencji IGK, a ja omówiłem dokładniej klasę Player z poprzedniego spotkania i zaprezentowałem prostą grę, którą napisałem wykorzystując poznaną już wiedzę.

Plan spotkania

  1. O konferencji IGK (Inżynieria Gier Komputerowych) - bazy danych noSQL
  2. Omówienie działania i założeń klasy Player z poprzedniego spotkania
    • Jej zadaniem jest dostarczenie podstawowego interfejsu gracza i opakowanie klasy zajmującej się animacją tekstury
  3. Pokazanie i omówienie prostej gry, którą każdy powinien już umieć napisać samemu :)
    • Sterowanie graczem
    • Strzelanie
    • Wczytywanie mapy z łańcucha string
    • Trywialny mechanizm kolizji

Materiały do tego spotkania

Wszystkie materiały (klasa Player oraz fantastyczna gra) znajdują się pod tym adresem:

materiały

Zachęcam do przejrzenia kodów źródłowych, ponieważ zawierają szczegółowe komentarze do wszystkich instrukcji. Poza tym projekt gry demonstruje podstawy użycia języka C#, co może być użyteczne dla osób początkujących.

 

Do tego spotkania powstało również nagranie. Jeśli zostanie ono zamieszczone w Internecie, podam do niego link.

 

Tags: ,

Kurs tworzenia gier XNA - spotkanie 1

by Filip 29. marca 2012 21:09

Zamieszczam materiały z 1 spotkania na temat tworzenia gier w XNA.

 

Plan spotkania:

  1. Wprowadzenie do XNA i Visual Studio 2010
    • każdy powinien założyć sobie konto na stronie https://www.dreamspark.com/
    • można z niej pobrać pełną licencję na Visual Studio, także dla użytku komercyjnego
  2. Szkielet gry w XNA
    • metody:
      • Initialize - inicjalizacja obiektów potrzebnych w naszej grze
      • LoadContent - załadowanie elementów takich jak dźwięk, czy obrazki z Content
      • UnloadContent - zwolnienie zasobów
      • Update - aktualizacja logiki gry (tutaj możemy przekazywać sterowanie do naszych obiektów)
      • Draw - rysowanie elementów
    • metody Update i Draw domyślnie wykonują się w pętli na przemian, 60 razy na sekundę (mechanizm gry stara się utrzymywać to na takim poziomie, jednak nie zawsze jest to możliwe) - można to zmienić w ustawieniach projektu
    • projektując klasę, która będzie brała istotny udział w interakcji z grą zwracamy uwagę na 3 płaszczyzny
      • inicjalizację - to wywołujemy w bloku Inicialize
      • aktualizację logiki - to wywołujemy w Update
      • rysowanie obiektu - to wywołujemy w Draw
  3. Rysowanie obiektu i poruszanie nim
    • aby narysować coś na ekranie używamy klasy SpriteBatch oraz metody Draw
      • wszystkie wywołania spriteBatch.Draw(...) powinny znajdywać się w bloku spriteBatch.Begin(); i spriteBatch.End();, wewnątrz metody Draw głównej klasy programu
    • poruszanie prostym obiektem można zrealizować poprzez sprawdzanie przyciśniętego klawisza wewnątrz metody Update i modyfikację jego współrzędnych
    • przykładowy projekt - GrupaNET.Tank
      • warto zwrócić uwagę na wspomniany podział na 3 płaszczyzny metod w klasie Tank
  4. Własna klasa do animacji postaci
    • zastosowanie w projekcie - GrupaNET.KlasaAnimacjiPostaci
    • klasa, którą napisał Paweł zajmuje się pocięciem obrazka z animacją, wybraniem odpowiedniej klatki, zapętlaniem i zmienianiem klatek
    • pozwala na ustalenie prędkości animacji
    • dobrze jest używać jej w swoim projekcie :)
  5. Opakowanie klasy animacji postaci w klasę Player
    • niestety nie zdążyliśmy tego pokazać na spotkaniu
    • wspaniała klasa Player, którą napisałem, pozwala na dodawanie wielu graczy z różnymi animacjami i sterowanie nimi dowolnymi klawiszami
    • zastosowanie w projekcie - GrupaNET.ChodzenieMultiplayer

Oto link do wszystkich materiałów, które wyprodukowaliśmy na spotkaniu:

Wszystkie materiały - spotkanie 1

Tags: ,

Konkurs Geek Club 2 + wskazówki

by Filip 29. marca 2012 20:50
Zamieszczam informację o nowym konkursie dla developerów Windows Phone:
 

Konkurs Geek Club 2

 
Zacznij już teraz pisać aplikacje, zgarnij telefon lub inne nagrody. Sprawdź co Cię czeka w nowej odsłonie akcji.

Wiesz jak pisać aplikacje na Windows Phone? A może chcesz
zacząć? Tylko teraz stwórz, opublikuj aplikację i zgarnij wyjątkowe nagrody!
Wśród nich telefony i promocja Twojej aplikacji w Marketplace. Masz czas do 31
maja 2012.

Jak wziąć udział w akcji?

  • Zarejestruj się na CodeGuru.pl lub WSS.pl
  • Dowiedz się, jak pisać aplikacje na Windows
    Phone
  • Pobierz narzędzia deweloperskie
  • Opublikuj aplikacje na Marketplace i zgłoś je na
    portalu CodeGuru lub WSS
  • Zgarnij wspaniałą nagrodę i zarabiaj na
    aplikacjach

Zasady są proste. Napisz aplikację, skupiając się na 3
punktowanych elementach:

  • Pomysł (400 pkt.)
  • Projekt graficzny (400 pkt.)
  • Implementacja (200 pkt.)

Twoja aplikacja przejdzie przez dwie fazy oceniania. W
pierwszej, dwóch testerów przyznaje jej punkty zgodnie z wytycznymi regulaminu.
Jeśli aplikacja otrzyma 600 (na 1000) punktów - przechodzi do drugiej fazy, w
której zostanie oceniona przez jury - pracowników Microsoft. W tej fazie za
aplikację zostanie przyznana ostateczna liczba punktów - maksymalnie 1000. 
Więcej informacji w regulaminie akcji: http://www.codeguru.pl/static/wp7.

 

Wskazówki:

  • Pomysł to także użyteczność i niepowtarzalność. Aplikacje przydatne, które chcemy zatrzymać na naszym telefonie oraz takie, których nie ma jeszcze na Marketplace są wyżej oceniane.
  • Aplikacja może być ciekawa pomimo że udostępnia tylko podstawową funkcjonalność.
  • Z drugiej strony mile widziane jest wykorzystywanie wszystkich udogodnień, które udostępnia Windows Phone (live tiles, notyfikacje, kafelki, launchers + choosers)
  • Oceniana jest tylko darmowa część aplikacji - jeśli Twoja aplikacja jest płatna, to ocenie w konkursie podlega jedynie trial.
  • Ocena za grafikę jest po części subiektywna jednak warto zwrócić uwagę na kilka szczegółów.
    • Aplikacja powinna podążać za stylem Metro (opisany w moim poprzednim poście) - jest to szczególnie brane pod uwagę.
    • Nie powinna naśladować interfejsów z innych urządzeń.
    • Wykorzystywanie domyślnych kontrolek udostępnianych przez Visual Studio jest mile widziane (oczywiście po odpowiednim wzbogaceniu i urozmaiceniu) - nie staramy się tworzyć własnych okienek / przycisków / panoram / czcionek od podstaw - wykorzystujemy to, co daje Silverlight.
    • Grafika powinna być czytelna!
    • Gry nie muszą być tworzone w stylu Metro - to dotyczy jedynie aplikacji użytkowych.
  • Implementacja oceniana jest w mniejszym stopniu - aplikacja działająca poprawnie i płynnie dostaje od razu 200 punktów, jednak łatwo stracić tu sporo, jeśli popełnimy jakieś błędy implementacyjne (na przykład niedziałający przycisk, źle działający application bar, źle rozwijana lista).
    • W szczególności, jeśli aplikacja w jakimś momencie rzuca wyjątek (crash aplikacji), program dostaje 0 punktów za implementację.

Tags: , ,

Szkolenie Imagine Cup w siedzibie Microsoft (ścieżka Windows Phone)

by Filip 25. lutego 2012 18:49

25.02.2012 w siedzibie Microsoft na Al. Jerozolimskich odbyły się dwa równoległe szkolenia związane z konkursem Imagine Cup (link do wydarzenia). Prelekcję na temat Windows Phone przeprowadził Bartłomiej Zass. Zamieszczę w tym wpisie moje notatki z tego wykładu.

 

Na temat projektowania i interfejsu Metro

Stylistyka Windows Phone składa wzoruje się na:

  • interfejsie Metro (Bauhaus school of design)
    • funkcjonalność
    • prostota
    • minimalizm
    • intuicyjność
    • czytelność
    • kafelki / kwadraty / surowe, ostre krawędzie
  • typografii
    • estetyka i zdobienie za pomocą fontów
  • kinematografii
    • dążenie do "ruchomości" wszystkich elementów
    • unikanie obiektów statycznych

Zarys elementów aplikacji

  • ekran główny
    • warto użyć widoku PANORAMA
    • powinien być czytelny / streszczony
    • tło powinno być subtelne
    • nie powinien mieć więcej niż 5 ekranów
    • należy unikać przewijania / rozwijania elementów w obu kierunkach - albo przewijamy na boki, albo w górę / dół
      • jeśli jakiś obiekt nie mieści się na całym ekranie, a chcemy zamieścić go jako jedną ze stron naszej panoramy, zamiast dodawać opcję scrollowania w dół, lepiej pozwolić na lekkie scrollowanie ekranu w bok
  • application bar
    • znajduje się na dole aplikacji
    • może być zminimalizowany
    • nie powinno go być na PANORAMIE, jeśli koniecznie chcemy go tam umieścić, powinien być zminimalizowany
  • pivot
    • slider z nagłówkami
    • nie powinien być używany w sposób "master-detail" (do wyboru podkategorii z innym pivotem)
  • przyciski
    • nie należy robić swoich przycisków "wstecz" oraz "powrót do ekranu głównego" ponieważ takie przyciski są już w telefonie
      • jeśli się na to zdecydujemy, powinniśmy zdjąć opuszczane strony ze stosu odwiedzin
  • kafelki
    • mogą mieć dwie strony
    • mogą mieć głębokie dowiązania do aplikacji oraz pobierać z niej informacje
    • mogą być aktualizowane przez notyfikacje push
    • w dobrym stylu jest używanie wielu life tiles

Hinty:

  • warto podążać tropem mody na kwadraty
  • należy unikać kopiowania stylu i designu z innych platform
  • unikać umieszczania kontrolki web browser w panoramie i pivocie
  • nie tworzyć własnych przycisków "zamknij", "wstecz", "powrót do menu"
  • unikać skalowania w obie strony

Linki:

Na temat agentów działających w tle i notyfikacji

WP7 udostępnia trzy rodzaje agentów

  • odtwarzacz muzyki
  • pobieranie plików
  • generic (wykonywanie kodu co 30 minut)
  • każda aplikacja może mieć po 1 z trzech agentów
  • na telefonie może działać jednocześnie kilkunastu agentów
  • użytkownik może wyłączyć agentów (limity te wynikają z oszczędności energii)

Launchers / choosers

  • pomagają dostać się do kalendarza / listy kontaktów
  • nie można napisać programu, który łączy się, lub wysyła SMS bez zgody użytkownika
  • zawsze akcję tego typu trzeba potwierdzić

Rozwiązanie pośrednie - można używać aplikacji z wygaszonym ekranem

Ograniczenia

  • w tle nie może działać aplikacja, jeśli rozmawiamy przez telefon lub odbieramy SMS
  • nie może działać kilka aplikacji
  • aplikacja nie może z tła wyświetlić okienka / wysłać SMSa / połączyć się z jakimś numerem (bez zgody użytkownika)
  • dwie aplikacje mogą komunikować się ze sobą jedynie poprzez chmurę

Notyfikacje Push

Trzy rodzaje notyfikacji

  • tile - zmiana wyglądu kafelka
    • działa tylko gdy aplikacja jest przypięta do głównego ekranu
    • nie może być dwóch kafelków z tym samym deep linkiem
  • raw - podczas działania aplikacji
  • toast - poprzez wyświetlenie klikalnego powiadomienia na pasku
    • nie mamy notyfikacji o kliknięciu przez użytkownika
  • dzięki nim można ominąć pewne ograniczenia związane z działaniem w tle
  • mogą być wysyłane częściej niż raz na 30 minut
  • kod wykonuje się nawet gdy aplikacja jest wyłączona, ale notyfikacja jest jedynie powiadomieniem
  • komunikaty są sformatowane w XMLu
  • nie wiemy nic o odebraniu notyfikacji
  • można używać Microsoft Push Notification Service

Tags: ,

Uzupełnienie do prezentacji z XNA

by anomaly 16. stycznia 2012 22:51

Zdaję sobie sprawę, że moja prezentacja w zeszły czwartek o podstawach XNA nie była najlepszej jakości, o czym najlepiej świadczy fakt, że Andrzej ciągle nie udostępnił jej do oceniania udostępnił ją do oceniania dopiero wtedy, gdy wszyscy zdążyli już o niej zapomnieć. Jej jakość wynikała z mojego małego doświadczenia w robieniu prezentacji i tego, że jej termin był okołosesyjny. Postaram się, by następna prezentacja była zdecydowanie lepsza, a do tego czasu postaram się uzupełnić parę informacji które zapomniałem podać i poprawić to, co, niestety, powiedziałem źle.

 

Rysowanie za pomocą spritebatcha:

Zapomnijcie o wszystkim co powiedziałem o ostatnim argumencie metody SpriteBatch.Draw. Działa on jak należy. Pokażę teraz przykład jak go wykorzystać, oraz powiem coś więcej o parametrze origin, bo też wydaje się, że nie powiedziałem o nim wystarczająco jasno.

Na początek stwórzmy dwa przykładowe prostokąty, będą one korzystały z tego samego prostokąta lokalizacji, ale drugi będzie miał origin w jego środku, co w przypadku kwadratu 50X50 oznacza punkt 25X25. Poniżej kod z którym zaczynamy.

using System;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
 
namespace SpriteBatchDrawing
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        private Texture2D pixel, pixel2;
        private float rotation;
        private KeyboardState oldState = Keyboard.GetState();
 
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }
 
        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            graphics.IsFullScreen = false;
            graphics.ApplyChanges();
            base.Initialize();
        }
 
        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            pixel = new Texture2D(GraphicsDevice, 1, 1);
            pixel.SetData<Color>(new Color[] { Color.White }); //Nie można zmieniać w trakcie.
            pixel2 = new Texture2D(GraphicsDevice, 50, 50);
            Color[] whiteBoard = new Color[50 * 50];
            for (int i = 0; i < 50 * 50; i++)
            {
                whiteBoard[i] = Color.White;
            }
 
            pixel2.SetData<Color>(whiteBoard); //Nie można zmieniać w trakcie.
        }
 
        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            pixel.Dispose();
            pixel2.Dispose();
            // TODO: Unload any non ContentManager content here
        }
 
        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (Keyboard.GetState().IsKeyDown(Keys.Escape))
                this.Exit();
 
            if (oldState.IsKeyUp(Keys.S) && Keyboard.GetState().IsKeyDown(Keys.S))
            {
                TakeScreenShot("ss");
            }
 
            // TODO: Add your update logic here
            rotation += 0.01f;
            base.Update(gameTime);
        }
 
        private void TakeScreenShot(string prefix)
        {
            int w = GraphicsDevice.PresentationParameters.BackBufferWidth;
            int h = GraphicsDevice.PresentationParameters.BackBufferHeight;
 
            //force a frame to be drawn (otherwise back buffer is empty)
            Draw(new GameTime());
 
            //pull the picture from the buffer
            int[] backBuffer = new int[w * h];
            GraphicsDevice.GetBackBufferData(backBuffer);
 
            //copy into a texture
            Texture2D texture = new Texture2D(GraphicsDevice, w, h, false, GraphicsDevice.PresentationParameters.BackBufferFormat);
            texture.SetData(backBuffer);
 
            //save to disk
            Stream stream = File.OpenWrite(prefix + "_" + Guid.NewGuid().ToString() + ".png");
            texture.SaveAsPng(stream, w, h);
            stream.Close();
            texture.Dispose();
 
        }
 
        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
 
            GraphicsDevice.Clear(Color.Black);
            Rectangle rec1 = new Rectangle(100,100,50,50);
            Rectangle rec2 = new Rectangle(100+25, 100+25, 50, 50);
 
            spriteBatch.Begin();
 
            spriteBatch.Draw(pixel2, rec1, null, Color.Red, 0, Vector2.Zero, SpriteEffects.None, 0.5f);
 
            spriteBatch.Draw(pixel2, rec1, null, Color.Blue, 0, new Vector2(25,25), SpriteEffects.None, 0.5f);
 
 
            spriteBatch.End();
            base.Draw(gameTime);
        }
    }
}

Na razie, gdy uruchomimy poniższy kod, naszym oczom powinien ukazać się następujący widok:

 

 

Jak widać na poprzednim screenie, prostokąt z ustawionym originem jest przesunięty względem czerwonego. Jest on narysowany tak, by współrzędne prostokąta, który jest drugim parametrem w wywołanej metodzie Draw, odpowiadały współrzędnym punktu przesuniętego od górnego lewego rogu prostokąta o origin. Dlatego defaultową wartością origin jest wektor zerowy i wtedy współrzędne drugiego parametru odpowiadają lokalizacji górnego lewego rogu rysowanej figury. Wszystko to odnosi się także, do metody Draw z drugim parametrem Vector 2,  oraz do metody DrawString.

Co więcej, gdybyśmy zmodyfikowali program i dali drugiemu prostokątowi pixel 1X1, to efekt byłby następujący

 

 

Jak widać program licząc origin nie bierze pod uwagę wymiarów prostokąta do którego dopasowujemy teksturę, tylko wymiary tekstury i jeżeli przekraczają one jej szerokość lub wysokość efekty mogą być nie najlepsze.Zmodyfikujmy zatem nasz program z powrotem, dodajmy 25 do współrzędnych drugiego prostokąta, by pokrywał się z pierwszym i dodajmy rotację do obu z nich.

protected override void Draw(GameTime gameTime)
        {
 
            GraphicsDevice.Clear(Color.Black);
            Rectangle rec1 = new Rectangle(100,100,50,50);
            Rectangle rec2 = new Rectangle(100+25, 100+25, 50, 50);
 
            spriteBatch.Begin();
 
            spriteBatch.Draw(pixel, rec1, null, Color.Red, rotation, Vector2.Zero, SpriteEffects.None, 0.5f);
 
            spriteBatch.Draw(pixel2, rec2, null, Color.Blue, rotation, new Vector2(25,25), SpriteEffects.None, 0.5f);
 
 
            spriteBatch.End();
            base.Draw(gameTime);
        }



Gdy uruchomimy zmieniony program oba prostokąty będą się obracać, ale nieco inaczej.






Jak widać, oba prostokąty rotują, ale nie tak samo. Oba rotują względem swojego parametru origin. W pierwszym przypadku, jest to wektor zerowy, czyli czerwony prostokąt rotuje wokół swojego lewego górnego rogu. Natomiast niebieski prostokąt rotuje wokół swojego środka.

Przejdźmy teraz do zagadnienia które, niestety, kompletnie zawaliłem na prezentacji - argumentu layerDepth.
Zapewne pamiętacie jak mówiłem, że ostatni parametr metody Draw decyduje o tym, który element będzie przesłaniał który i że to źle działa. Otóż, działa to jak najbardziej poprawnie, tylko wyszła tam moja ignorancja.

Otóż metoda spritebatch.begin ma parę różnych wersji. Nas interesuje jedna z nich, a mianowicie.

spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.Opaque);


Jak widać metoda przyjmuje dwa parametry.

SpriteSortMode decyduje o kolejności rysowania spritów.

Deterred - sprity rysowane są w kolejności wystąpienia oraz są rysowane dopiero po wywołaniu End() - opcja defaultowa
BackToFront / FrontToBack - są rysowane tak jak w deterred, tylko są odpowiednio sortowane względem layerDepth, gdzie 1 to background a 0 to foreground.
Textute - są rysowane tak jak w deterred, tylko są sortowane po użytych teksturach
Immidiate - rysowanie spritów następuje od razu, bez czekania na spritebatch.End()

Natomiast argument typu BlendState odpowiada za to jak łączone są już zapisane piksele z nowo powstającymi:
Additive -dodawanie kolorów do siebie. W naszym przykładzie z niebieskim i czerwonym kwadratem w tym samym miejscu da to następujący efekt.

 

Inne w tym przykładzie zadziałają tak samo, więc nie będę o nich pisać.

Teraz, gdy wybierzemy np. SpriteSortMode.BackToFront ostatni argument będzie jak najbardziej brany pod uwagę.

To tyle (mam nadzieję) jeżeli chodzi o moje kompromitujące pomyłki, więc przejdę teraz do rzeczy, o których zapomniałem powiedzieć.

Skalowanie spritów:

Metoda Spritebatch.Draw dla zwykłych tekstur, których nie chcemy rozciągać do prostokąta ma dodatkowo parametr Scale (zarówno w wersji float jak i Vector 2), dzięki której można rozszerzać i zmniejszać daną teksturę równomiernie w obu kierunkach (float) lub też np. tylko w jednym
(wersja z Vectorem2).

Więcej o klasie GameComponent:


GameComponent (i dziedziczący po nim DrawableGameComponent) ma pole IsEnabled, które określa, czy dany komponent powinien być aktualizowany w danym updacie - użyłem tego do wyłączenia prawie wszystkich komponentów, gdy gracz pauzuje grę (Prawie wszystkich, bo musimy aktualizować input wprowadzany przez gracza.)

Dodatkowo GameComponent ma pole UpdateOrder, w którym możemy ustawić wartość określającą kiedy komponent będzie updatowany (przypominam, że update komponentów odbywa się w base.Update() w klasie gry). Komponent z mniejszą wartością zostanie wywołany wcześniej. Dodatkowo istnieje też zdarzenie UpdateOrderChanged.

 

Na koniec słowo o metodzie TakeScreenShot(), która zapisuje screenshot do pliku .png. Aby móc wykorzystać tą metodę, należy zmienić Game Profile na HiDef. Aby to zrobić klikamy prawym przyciskiem myszy na projekt w Solution Explorer. Następnie wybieramy z rozwijanego menu opcję Properties. Wybieramy zakładkę XNA Game Studio i tam wybieramy odpowiedni profil.

 

Na ten wpis to wszystko, jeżeli udało mi się zepsuć prezentację jeszcze bardziej piszcie śmiało w komentarzach, postaram się odpowiedzieć.

W załączniku umieściłem projekt który zrobiłem na zeszłoczwartkową prezentację.

XNAPodstawy.zip (3,92 mb)

Tags:

Piszemy w XNA!

by Wąsik 15. stycznia 2012 19:00

Dziś stworzymy prostą gierkę w XNA jaką jest slider kafelków, które tworzą jeden cały obraz. Naszym zadaniem będzie przesuwanie kafelków w taki sposób, aby stworzyły kompletny obraz. Wymagana znajomość XNA (na litość boską, choć trochę.. albo i więcej) Zaczynajmy.

Koncept intersejfu:

Jak więc widać - nasz główny obraz będzie rozmiaru 450x450 px oraz składał się z 25 kafelków (dokładnie 24, jeden bedzię pusty). Jeden kafelek będzie miał 450*450/25 = 90 px.

Przepraszam za błędne dane na rysunku ale zrobiłem to zanim policzyłem dane - lepiej żeby wymiary były całkowite :)

Teraz przejdźmy do konceptu struktury programu.

-Główna klasa programu

-Klasa reprezentująca jeden kafelek obrazu

-Klasa reprezentująca obraz złożony z 25 kafelków klasy powyżej

 

Ok - stwórzmy więc nowy projekt w VS2010 (oczywiście XNA dla WP 7.1). Nazwa dowolna. 

Zajmijmy się teraz bazową klasą reprezentującą pojedynczy kafelek, którą nazwiemy Tile.

Teraz dodajmy następujące pola globalne:

private const int WIDTH = 90; //rozmiar kafelka

private Vector2 _position; //pozycja kafelka względem początku obrazu (wektor)
private Vector2 _positionInImage; //pozycja prostokąta, w którym przechowywany jest oryginalny kawałek obrazka
private Vector2 _newPosition; //nowy pozycja, na którą kafelek ma się przesunąć
public bool _isEmpty = false; //flaga, czy kafelek powinien być pustym
private TimeSpan _framerate; //czas mmiędzy wiświetlaniem kolejnych klatek

Nasz pojedynczy kafelek będzie reprezentować 3 wektory. Wektor _position będzie odpowiadać za pozycję kafelka względem początku obrazka, _positionInImage będzie oznaczać stały fragment lewego górnego prostokąta 90x90 z oryginalnego obrazka (czyli jeszcze nie pomieszanego) a natomiast _newPosition będzie oznaczać wektor, na który nasz kafelek powinien się przesunąć (wygodne przy tworzeniu animacji). 

Natomiast _framerate będzie zmienną przechowywującą swojego rodzaju czasomierz, który odlicza czas od upłynięcia poprzedniej klatki (dzięki nie niemu będziemy przemieszczać klocek np. 3 razy na sekundę,  a nie 33 (tyle jest klatek na sekundę domyślnie) - co by było za szybko.

Przejdźmy teraz do konstruktora naszej klasy Tile:

public Tile(Vector2 position, Vector2 positionInImage)
{
_position = position; //inicjujemy zmienne
_newPosition = position;
_positionInImage = positionInImage;
_framerate = TimeSpan.FromMilliseconds(0); 
}

Powinien on się wydawać dość prosty :)

Teraz kilka przydatnych metod:

public Vector2 GetPositionInImage 
//opisujemy którą cześć obrazka kafelek przechowywuje
{
 get { return _positionInImage; }
}

public void Move(Vector2 vector)
//ustalamy na którą pozycję kafelek powinien się przesunąć
{
  _newPosition = vector;
}

public Vector2 GetTheVector
//zwracmy pozycję kafelka albo pozcyję, na którą dopiero dąży
{
 get
  {
     return _newPosition;
    }
}

public Vector2 GetOldTheVector
//zwracamy pozycję kafelka albo pozycję z której zaczął animacje
 {
    get
      {
            return _position;
       }
 }

public bool IsMoving()
//jeśli wektor starego położenia jest różny od tego z nowym położenim, to znaczy że jesteśmy w trakcie animacji
{
   return _position != _newPosition;
}

public void SetTheVector(Vector2 vector)
//ustawiamy pozycję kafelka, pomijając animację
{
 _position = vector;
  _newPosition = _position;
}

public bool Conflict(int x, int y, Vector2 globalVector)
//sprawdza, czy zadane punkty znajdują się w obrębie kafelka. Potrzebne będzie do reagowania na dotyk użytkownika. Współrzędne położenia palca pobierzmy z zewnątrz.
{
  //tworzymy prostkokąt w okół zadanej współrzędnej o wymiarach 4x4, gdzie zadany punkt znajduje się dokładnie w jego środku
   var collision = new Rectangle((int)_newPosition.X + (int)globalVector.X, (int)_newPosition.Y + (int)globalVector.Y, WIDTH, WIDTH); 
 //metoda intersects sprawdza, czy dwa prostokąty są w kolizji i zwraca wartość logiczną
            return collision.Intersects(new Rectangle(x-2, y-2, 4, 4));
}

public void Draw(SpriteBatch sprite, Texture2D image, Vector2 globalImage)
  //rysujemy pojedynczą klatkę
{
     if (_isEmpty) return; //jeśli nasz kafelek jest pusty, to opuszczamy procedurę rysowania
 //klasa sprite reprezentuje zbiór method do rysowania na ekranie
      sprite.Begin(); //rozpocznij proces rysowania
      sprite.Draw(image, (globalImage + _position), new Rectangle((int)_positionInImage.X, (int)_positionInImage.Y, WIDTH, WIDTH), Color.White, 0, Vector2.Zero, 1, SpriteEffects.None, 0);
//(globalImage + _position) - wektor położenia całego obrazka dodany do położenia kafelka względem obrazka dam nam położenia kafelka względem całego ekranu
//new Rectangle((int)_positionInImage.X, (int)_positionInImage.Y, WIDTH, WIDTH) - wycinamy odpowiedni kawałek z oryginalnego obrazka o wymiarach 90x90)

        public void Update(GameTime gameTime)
//aktualizujemy logikę kafelka
        {
            _framerate -= gameTime.ElapsedGameTime; //aktualizujemy czas pozostały do następnej klatki

            if (_position != _newPosition && _framerate.TotalMilliseconds <= 0) //jeżeli mamy zmienić pozycję i nastąpił czas aktualizji animacji
            {
                if (_position.X > _newPosition.X) _position.X -= 5; //przesuwamy w dół jeśli trzeba;
                if (_position.X < _newPosition.X) _position.X += 5; //przesuwamy w górę jeśli trzeba;
                if (_position.Y > _newPosition.Y) _position.Y -= 5; //przesuwamy w lewo jeśli trzeba;
                if (_position.Y < _newPosition.Y) _position.Y += 5; //przesuwamy w prawo jeśli trzeba;
                _framerate = TimeSpan.FromMilliseconds(25); /odliczamy teraz 25 ms aby narysować nastepną klatkę 
            }
        }
       sprite.End(); //konczymy rysowanie
}

Ok - nasza klasa bazowa Tile została ukończona. Teraz przydałoby się stworzyć jakąś klasę, która będzie koordynować nasze 25 kafelków. Nazwiemy ją GameBoard. Jak zwykle zmienne:

private List<Tile> _container; // przechowywujemy tutaj nasze kafelki;
        private Texture2D _mainImage; //zmienna przechowywująca naszą teksturę
        private Vector2 _emptyVector; //wskaźnik na jeden pusty kafelek - ułatwi nam to nawigowanie
        private readonly SpriteBatch _sprite; //menager do rysowania
        private readonly Vector2 _globalVector; //główny wektor położenia naszej planszy - czyli głównego obrazka

Kontruktor naszej nowej klasy:

public GameBoard(Texture2D image, SpriteBatch sprite, Vector2 globalVector)
        {
            _mainImage = image; //aktualizujemy teksturę
            _container = new List<Tile>(); //tworzymy nową listę
            _sprite = sprite; //oraz przekazujemy menagera.

            for (var j = 0; j < 5; j++)
            {
                for (var i = 0; i < 5; i++) //tworzymy 25 kafelków obok siebie. wektory wskazują na lewy górny róg pojedynczego kafelka. Chwilo obraz nie jest jeszcze "pocięty" więc fragment oryginalnego obrazka ma taki sam wektor położenia w obrazku jak położenie kafelka
                {
                    var item = new Tile(new Vector2(j * 90, i * 90), new Vector2(j * 90, i * 90));
                    _container.Add(item);
                }
            }
            _emptyVector = new Vector2(0, 0); //nasz pusty kafelek (lewy górny róg)
            _container[0]._isEmpty = true;
            _globalVector = globalVector; //położenie całego obrazka
        }

Teraz zajmijmy się pojedynczymi metodami:

public void SetNewMainImage(Texture2D image)
//zmieniamy obrazek, który jest "pocięty".
        {
            _mainImage = image;
        }

        public void Solve()
//ustawia kafelki ustawia tak, aby tworzyły kompletny obrazek, animując je przy okazji
        {
            foreach (var tile in _container)
            {
                tile.Move(tile.GetPositionInImage); //przesuwamy każdy kafelek, na tą pozycję, na której położony jest fragment obrazu który przetrzymuje
            }

            _emptyVector = FindEmpty();

        }

        private List<E> ShuffleList<E>(List<E> inputList)
//metoda pomocnicza, sortuje listę dowolnego typu
        {
            var randomList = new List<E>();
            var r = new Random();

            while (inputList.Count > 0)
            {
                var randomIndex = r.Next(0, inputList.Count);
                randomList.Add(inputList[randomIndex]); //add it to the new, random list
                inputList.RemoveAt(randomIndex); //remove to avoid duplicates
            }

            return randomList; //return the new random list
        }

        public void ShuffleTiles(bool animationEnabled)
//losuje listę wektorów położenia
        {
            var vectorList = _container.Select(item => item.GetTheVector).ToList();
//budujemy najpierw listę wektorów poło��enia kafelków za pomocą wyrażenia LINQ           
 vectorList = ShuffleList(vectorList); //losujemy
            for (var i = 0; i < vectorList.Count; i++) if (!animationEnabled) _container[i].SetTheVector(vectorList[i]); else _container[i].Move(vectorList[i]);
  //aktualizujemy położenia kafelka (ustawiamy mu nową pozycję wraz z odtworzeniem animacji
            _emptyVector = FindEmpty(); //szukamy pozycji pustego kafelka
        }

        public void Draw()
//rysujemy po kolei każdy kafelek
        {
            foreach (Tile t in _container) t.Draw(_sprite, _mainImage, _globalVector);
        }

        private Vector2 FindEmpty()
//szukamy pustego kafelka i zwracamy wektor jego położenia
        {
            var i = 0;
            for (; i < _container.Count; i++)
            {
                var tile = _container[i];
                if (tile._isEmpty) return tile.GetTheVector;
            }

            return Vector2.Zero;
        }

private bool MoveIsAvailable(Tile tile, out Vector2 vector)
//metoda sprawdza czy w sąsiedztwie zadanego kafelka jest puste miejsce (aby przesunąc) i w razie jeśli tak, to zwraca położenie tego pustego miejsca
        {

            if (((int)_emptyVector.X + 90 == (int)tile.GetTheVector.X && (int)_emptyVector.Y == (int)tile.GetTheVector.Y) |
               ((int)_emptyVector.X - 90 == (int)tile.GetTheVector.X && (int)_emptyVector.Y == (int)tile.GetTheVector.Y) |
               ((int)_emptyVector.X == (int)tile.GetTheVector.X && (int)_emptyVector.Y + 90 == (int)tile.GetTheVector.Y) |
               ((int)_emptyVector.X == (int)tile.GetTheVector.X && (int)_emptyVector.Y - 90 == (int)tile.GetTheVector.Y))
            {
                vector = _emptyVector;
                return true;
            }
            else
            {
                vector = Vector2.Zero;
                return false;
            }
        }

        public Tile FindEmptyTile()
//zwraca pusty kafelek
        {
            foreach (var item in _container)
            {
                if (item._isEmpty) return item;
            }
            return null;
        }

 public void Update(GameTime gameTime)
//aktualizuje logikę wszystkich kafelków
        {
            var touches = TouchPanel.GetState(); //pobierz wszystkie punkty dotyku ekranu przez użytkownika

            foreach (var item in _container) //aktualizujemy każdy kafelek osobno
            {
                if (touches.Count == 1) //jeśli mamy jeden punkt dotyku
                {
                    if (item.Conflict((int)touches[0].Position.X, (int)touches[0].Position.Y, _globalVector)) //jesli kafelek został dodatknięty
                    {
                        Vector2 position;
                        if (MoveIsAvailable(item, out position) && !item.IsMoving())
//sprawdzmy, czy jest pusty kafelek obok
                        {
                            _emptyVector = item.GetOldTheVector;
                            FindEmptyTile().SetTheVector(_emptyVector);
                            item.Move(position); //przeuswamy kafelek i aktualizujemy położenie pustego
                        }
                    }
                }

                item.Update(gameTime); //aktualizujemy odrębną logikę kafelka (animacje)
            }
        }

Zostało nam teraz już tylko napisać główny kod programu, który znajdziecie tutaj (sposób jaki jak przechowywuje i aktualizuje dane może być nietrywialne ;P)

public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        private GameBoard _gameBoard;
        private readonly Vector2 globalVector = new Vector2(15, 800 - 450 - 15);

        private int _currentImage = 0; //numer głownego obrazka, może być kilka

        private List<Texture2D> _imagesList = new List<Texture2D>(); //lista głównych obrazków
        private Texture2D _arrowText; //tekstury przycisków,
        private Texture2D _shuffleButtonText;
        private Texture2D _bg;
        private Texture2D _solve;
        private SoundEffect _tapSound; //efekt dźwiękowy musi być, może załapie się jeszcze w GeekClubie :D

//położenia wszystkich głównych elementów na ekranie
        private Rectangle _lArrow = new Rectangle(480 - 100 - 15, 15, 100, 100);
        private Rectangle _rArrow = new Rectangle(15, 15, 100, 100);
        private Rectangle _shuffleButton = new Rectangle(100+15+25, 15, 200, 100);
        private Rectangle _solveRect = new Rectangle(15,115, 450, 100);

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this) {PreferredBackBufferWidth = 480, PreferredBackBufferHeight = 800}; //odpowiednie wymiary ekranu wybieramy
            graphics.ApplyChanges();

            Content.RootDirectory = "Content";
            TouchPanel.EnabledGestures = GestureType.Tap;
            TargetElapsedTime = TimeSpan.FromTicks(333333);

            InactiveSleepTime = TimeSpan.FromSeconds(1);
        }

        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();
        }


        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

//bezczelnie ładujemy dane z plików
            for (int i = 1; i <= 8; i++ )
            {
                Texture2D item = Content.Load<Texture2D>("images/" + i);
                _imagesList.Add(item);
            }

            _arrowText = Content.Load<Texture2D>("images/larrow");
            _shuffleButtonText = Content.Load<Texture2D>("images/shuffle");
            _bg = Content.Load<Texture2D>("images/bg");
            _solve = Content.Load<Texture2D>("images/solve");
            _tapSound = Content.Load<SoundEffect>("tap");

             _gameBoard = new GameBoard(_imagesList[_currentImage], spriteBatch, globalVector); //towrzymy sobie plansze
            _gameBoard.ShuffleTiles(false); //mieszamy kafelki, bez animacji (bo po co przy starcie?)
        }

  
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
//olać pamięć :D
        }


        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            _gameBoard.Update(gameTime); //aktualizujemy plansze

            while (TouchPanel.IsGestureAvailable) //śmieci - sprawdzmy tylko czy jakiś przycisk nie został "tap"nięty i jak coś obsługujemy zdażenie
            {
                var gesure = TouchPanel.ReadGesture();

                Rectangle touchRect = new Rectangle((int)gesure.Position.X - 2, (int)gesure.Position.Y - 2, 4, 4);

                if (touchRect.Intersects(_lArrow) && _currentImage < _imagesList.Count - 1)
                {
                    _currentImage++; 
                    _gameBoard.SetNewMainImage(_imagesList[_currentImage]);
                    _tapSound.Play();
                }
                else if (touchRect.Intersects(_rArrow) && _currentImage > 0)
                {
                    _currentImage--;
                    _gameBoard.SetNewMainImage(_imagesList[_currentImage]);
                    _tapSound.Play();
                }
                else if (touchRect.Intersects(_shuffleButton))
                {
                    _gameBoard.ShuffleTiles(true);
                    _tapSound.Play();
                }
                else if (touchRect.Intersects(_solveRect))
                {
                    _gameBoard.Solve();
                    _tapSound.Play();
                }
            }

            base.Update(gameTime);
        }

 
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin(); //rysujemy przyciski, tło, plansze.
            spriteBatch.Draw(_bg, Vector2.Zero, Color.White);
            spriteBatch.Draw(_solve, _solveRect, Color.White);
            spriteBatch.Draw(_arrowText, _lArrow, Color.White);
            spriteBatch.Draw(_arrowText, _rArrow, null, Color.White, 0, Vector2.Zero, SpriteEffects.FlipHorizontally, 0);
            spriteBatch.Draw(_shuffleButtonText, _shuffleButton, Color.White);
            spriteBatch.End();

            _gameBoard.Draw();

            base.Draw(gameTime);
        }
    }

Uff.. pewnie dużo nierozumiałego kodu, namieszanego, nieoptymalnego.. ale co tam, ważne że działa:

Jeśli filmik z youtube nie działa, to klik.

Wrzucone przeze mnie na marketplace'a, może się przyjmie :)

Powodzenia w kompilowaniu, w razie co zawalać pytaniami Money mouth

Tags:

System kontroli wersji - SVN oraz Visual Studio

by endrju 14. stycznia 2012 00:39

Dzisiejszy wpis będzie poświęcony przechowywaniu naszego projektu z Visual Studio w repozytorium. Repozytorium jest miejscem, gdzie przechowujemy uporządkowane pliki, pamiętając historię zmian ze szczegółami, możliwością cofania się do przeszłej wersji. Aby w pełni cieszyć się możliwościami repozytorium potrzebny nam będzie system kontroli wersji, który udostępni nam wachlarz funkcji. W naszym przypadku będzie to Subversion, inaczej SVN. Akurat ten produkt został wybrany z powodu łatwiejszej kontroli zmianami projektu oraz ilością dodatków do Visual Studio wspierających pracę z repozytorium.

Zacznijmy od wymagań. Posłużę się dwoma narzędziami, które są w pełni darmowe:

1.       TortoiseSVN – http://tortoisesvn.net/downloads.html

2.       AnkhSVN - http://ankhsvn.open.collab.net/downloads

Jak już zainstalujemy oba programy będziemy potrzebowali zdalnego repozytorium, chybaże chcemy postawić to na własnym komputerze J

Pierwszą opcją jest skorzystanie z uczelnianego SVN. Wystarczy wysłać prośbę do labolatorium podając nazwę, loginy użytkowników. Więcej informacji na lk.mimuw.edu.pl

Alternatywą jest skorzystanie z zewnętrznych serwisów oferujących repozytorium SVN. W większości przypadków otrzymamy wiki, issue tracker itd. Opcją jest codeplex.com (wszystkie projekty są publiczne!), bądź xp-dev.com (istnieją projekty prywatne do 100mb).

Wybór należy do Was J

Najważniejsze rzeczy za nami, teraz czas na zabawę w commit-y i update-y.

Pokażę Wam jak pobrać i pracować na projekcie, który sami stworzycie i wrzucicie do repozytorium oraz jak pobrać i zintegrować VS do pracy z projektem, który jest już w repozytorium.

Opcja 1.

1.      1.  Otwieramy Visual Studio oraz wybieramy New Project.

2.       2. Wprowadzamy dane i zaznaczamy Add to Subversion

3. Zostaniemy poproszenie o wprowadzenie danych dotyczących SVN.

3.       

1.       Nazwa projektu

2.       Adres repozytorium

3.       Miejsce w repozytorium, gdzie umieścimy nasz projekt

4.       Zatwierdzamy OK

UWAGA! Podczas wykonywania tych operacji będziemy musieli podać dane do zalogowania się do repozytorium!

4. Podajemy opcjonalnie informacje dotyczące naszego projektu, które będą dostępne w repozytorium.

5.       Jak już uda nam się dodać projekt do repozytorium będziemy chcieli kontrolować wszelkie zmiany w nim. Aby ułatwić do wybieramy z menu View -> Pending Changes.

6.       Naszym oczom ukarze się nowe okienko, gdzie będziemy widzieć jakie pliki zostały zmienione lokalnie od ostatniego Update z repozytorium.

1.       Wrzuca zaznaczone pliki do repozytorium wraz z podaną wiadomością

2.       Pobiera najnowszą wersję z repozytorium

3.       Informacja dotycząca commit-a

4.       Pliki zmienione lokalnie od ostatniego update-a

UWAGA! Jeśli dwaj użytkownicy będą równocześnie edytować jeden plik mogą powstać konflikty. Program nas o tym poinformuje i sam spróbuje rozwiązać problem poprzez merge.

Udało nam się opanować podstawy wrzucania projektu do repozytorium.

Teraz czas na pobierania projektu już istniejącego w Repozutrium.


Opcja 2.

1.       Wchodzimy do katalogu, gdzie będziemy chcieli trzymać nasz projekt oraz klikamy prawym przyciskiem myszy. Naszym oczom ukażą się opcje związane z kontrolą wersji.

2.       Wybieramy SVN Checkout, aby pobrać nowy folder (projekt) z repozytorium SVN.

3.       Wypełniamy dane.

1.       Adres do naszego projektu w repozytorium

2.       Miejsce gdzie chcemy zrobić checkout

3.       Opcje dotyczące głębokości pobrania folderów

4.       Opcja dotycząca wersji SVN projektu, którą chcemy pobrać

5.       Zatwierdzamy OK.

4. Pobraliśmy nasz nowy projekt i możemy z nim pracować jak w pierwszej opcji.

Jeśli wejdziemy do katalogu, gdzie znajduje się projekt pod kontrolą SVN to możemy sprawdzić, czy posiadamy najnowszą wersję z repozytorium.

a.       Zielone kółko oznacza zgodność z HEADem, czyli najnowszym commit-em

   

b.      Czerwone kółko oznacza, że wystąpił nowszy commit i należy zrobić update.

    

 

To na tyle, mam nadzieję, że choć trochę zaznajomiłem Was z systemem kontroli wersji SVN oraz możliwościami integracji z SVN.

W razie pytań piszcie na mail.

Zapraszam do komentowania J 

Tags:

UAC w aplikacji

by Wąsik 13. stycznia 2012 20:10

Czasami, pisząc nasze aplikacje w Visual Studio, potrzebujemy wymusić uruchomienie aplikacji z uprawnieniami administratora - gdyż chcemy przeprowadzić jakieś zaawansowane operacje. Operacje jak zapis w rejestrze, czy zapisywanie plików w specjalnych katalogach. 

Domyślnym sposobem wymuszenia uruchomienia aplikacji z UAC'em jest podpisanie aplikacji certyfikatem oraz utworzenie specjalnego zewnętrznego pliku manifest.  Visual Studio umożliwia nam przeprowadzenie tych operacji prawie automatycznie, włącznie z wbudowaniem pliku manifest w nasze assembly. 

Utwórzmy sobie przykładowy projekt, lub otwórzmy już zrobioną aplikację. Następnie przechodzimy do Project -> Add new item..

Z widocznego okna wybieramy pozycję Application Manifest File.

Otwiera nam się w edytorze nasz plik manifest, który automatycznie został dodany do Project Solution. Szukamy wpisu (mniej więcej w środku pliku):

Teraz podajemy własne wartości w polu level:

asInvoker - aplikacja zostanie uruchomia z domyślnymi uprawnieniami

highestAvailable - aplikacja zostanie uruchomiona z najwyższymi uprawnieniami, jakie są dostępne

requireAdministrator - aplikacja zostanie uruchomina tylko i wyłącznie z uprawnieniami administratora. Jeśli to nie jest możliwe (np. użytkownik nie ma prawa uzyskać praw administratora) aplikacja nie zostanie uruchomiona.

Uwaga: jeśli wybierzemy requireAdministrator, to przed pierwszym debugowaniem Visual Studio sam poprosi o uruchonienie samego siebie w trybie administratora - jeśli potwierdzimy - zrestartuje się z odpowiednimi uprawnieniami. Inaczej nie będziemy mogli uruchomić debugowania.

Działa tylko w Windows 7 oraz Vista.

Tags:

Nasze aplikacje

by Wąsik 13. stycznia 2012 00:48

Lista wydziałowych aplikacji

Aktualizacja: lista znajduje się tutaj. Można również przejść na podstronę z odpowiedniego menu z boku.

Tags:

O grupie

Prężnie rozwijąca się grupa .NET funkcjonująca na Wydziale MIM na Uniwersytecie Warszawskim.

Month List