Мутим ИгроПУСК

Превращаем кнопку ПУСК в игро-шарик :)

Мутим ИгроПУСК

Автор: John Frost
ICQ: 488-251

СКАЧАТЬ ИХОДНИК

Кнопка «Пуск» — с ней мы сталкиваемся каждый день, она уже настолько привычная вещь, как монитор, клава и мышь. Большинство офисного планктона, вообще не может представить работу с компом без этой заветной кнопочки – как же еще запустить косынку, тьфу, эксэль, кроме как этим способом smile
С момента появления 95 форточки в Интернете можно было найти миллион и один способ как поиздеваться над бедным пуском – начинаю от безобидного скрытия – до убегания от курсора мыши. Но чтобы не повторятся, мы сделаем эксклюзив. Все мы знаем знаменитую игру пинг-понг. Для тех в танке (прости Алекс smile) объясню — есть шарик и две ракетки, оба противника отбивают шарик, скорость постепенно нарастает, кто пропустит – тот и проиграл. Плагиатить полностью идею мы не будем, а попробуем скреативить что-нибудь свое.
В пинг-понге шарик отскакивал от стен, а мы сделаем рандомную ситуацию – пусть либо он отскочит от стены, либо выскочит из другой стенки – это предаст игры больше неожиданности. Теперь мы можем спокойно убрать ракетку противника и сделать отскок от «потолка». Противника заменит нам постоянно увеличивающиеся скорость и возможность прохождения/отскока от стены.
Учитывая условия игры – победить здесь будет нельзя, игра будет на время, типа кто дольше продержится. Значит придется отслеживать время, также например каждые пять секунд мы будем увеличивать скорость шарика.
Закончим рассуждения – приступаем к кодингу.
Для начала делаем новый проект на шарпе, убераем у формы ControlBox, отключаем показ окна в панели задач, кидаем Label на форму, заливаем фоном любой клевый цвет.Должно получится примерно что и на рисунке.

Мутим ИгроПУСК

Теперь нам понадобится три таймера:
1)MainTimer – ставим на 10 мс, с помощью этого таймера будем производить основной цикл игры, перемещения и логика.
2)Time – ставим на 1000 мс, что равно примерно 1 секунде. Этот таймер будет отслеживать время игры, чтобы в конце показать результат.
3)Speed – ставим на 5000 мс. Теперь этот таймер будет каждые 5 секунд увеличивать скорость шарика-пуска.

Властелин окон
Для того чтобы управлять кнопкой пуск нужно:
1)Найти панель задач, это делается WinAPI-функцией FindWindow. Ей передается название класса и заголовок окна.
2)Получить указатель на копку пуск функцией GetWindow, этой функции передается указатель на панель задач и еще один параметр, указывающий, какое именно окно надо получить.
3)Разорвать связь с панелью задач и пуском функцией SetParent. Надо указать в качестве первого параметра указатель на пуск, а во втором указатель на окно, к которому будет принадлежать наш пуско-шарик, в нашем случае указываем 0.
Для перемещение окна нам понадобится функция SetWindowPos, ей нужно передать указатель на нужное окно, координаты х и у координат, ширину, высоту окна и специальные флаги отображения. Также нам понадобится функция ShowWindow, позволяющая скрывать или отображать окно.
Для начала нам нужно импортировать эти функции из библиотеки user32.dll.

[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string WindowClassName, string Caption);
[DllImport("user32.dll")]
public static extern IntPtr GetWindow(IntPtr hwnd,uint uCMD);//GW_CHILD=5
[DllImport("user32.dll")]
public static extern IntPtr SetParent(IntPtr hwndChild, int parent);
[DllImport("user32.dll")]
public static extern bool SetWindowPos(IntPtr hwnd, int pos,int x,int y,int cx,int cy,uint uFlags);//HWND_TOPMOST=-1, SWP_SHOWWINDOW=0x0040
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr HWND, uint uCMD);//SW_SHOW=5
Чтобы этот код работал нужно прописать в начале это:

using System.Runtime.InteropServices;

Для того чтобы, отслеживать логику игры, объявим переменные, назначения объяснять не буду – там хорошие комменты.

Random RND = new Random();//создаем объект для рандомизации
IntPtr pusk;//указатель на кнопку пуск
float opacity=1.0f;//переменная для изменения прозрачности окна
int x=500,y=500;//х и у координаты
int xplus = 1;//ускорение по х-коордмнате
int yplus = 1;//ускорение по у-координате
int cx;//ширина
int cy;//высота
int time;//тут будет хранится кол-во времени  игры
int xnapr = 1;//направление по х-координате, влево или направо
int ynapr = 1;//направление по у-координате, вниз или вверх

Отлавливаем событие загрузки формы и прописываем там такой код:

private void Form1_Load(object sender, EventArgs e)
        {
            //изменяем ширину нашего окна, в зависимости от разрешения экрана
            this.Width = Screen.PrimaryScreen.Bounds.Width / 10;
           //делаем ширину пуска, треть от ширины нашего окна
            cx = this.Width / 3;
            cy = this.Height;
            //устанавливаем максимальный размер нашего окна и положение
            this.MaximumSize = new Size(this.Width, this.Height);
            this.Location = new Point(Screen.PrimaryScreen.Bounds.Width / 4, Screen.PrimaryScreen.Bounds.Height-this.Height*2);
            //ищем панель задач
            pusk = FindWindow("Shell_TrayWnd", null);
            //берем оттуда пуск
            pusk = GetWindow(pusk, 5);
            //"отдираем" от панели задач :)
            SetParent(pusk, 0);
            //ставим на (100,100)
            SetWindowPos(pusk, -1, 100, 100, cx , cy, 0x0040);
           //отображаем, хотя и необязательно
            ShowWindow(pusk, 5);
           }

Пишем основную логику
Как выделяется хорошая игра, кроме сюжета и графики? Конечно же дополнительными деталями, так называемым «блеском». Что мы можем эдакого добавить? Например можно оставить просто обычную ракетку, а можно создать эффект мигания – форма до определенного момента становится прозрачной, затем опять до не прозрачной. Получается интересный эффект. Делается это таким образом:
/

/изменяем динамически прозрачность, эффект мигания
if (opacity >= 0.5)
      this.Opacity = (opacity-=0.01f);
else opacity = 1.0f;

Затем мы должны передвигать нашу «ракетку» в зависимости от положения мыши, делается это элементарно:

this.Location = new Point(MousePosition.X-10, this.Location.Y);

Теперь пропишем логику взаимодействия пуска со стенами:

//проверяем х-координату пуска на выход за правый край монитора
            if (x + cx > Screen.PrimaryScreen.Bounds.Width)
            {
               //или выходим с другой стены
                if (RND.NextDouble() > 0.5)
                    x = 1;
                //или меняем направление
                else
                {
                    x = Screen.PrimaryScreen.Bounds.Width - cx;
                    xnapr = -xnapr;
                }
            }
            //проверяем х-координату на выход за левый край моника
            if (x < 1)
            {
                //или выходим с другой стены
                if (RND.NextDouble()>0.5)
                    x = Screen.PrimaryScreen.Bounds.Width;
                //или меняем направление
                else
                {
                    x = 1;
                    xnapr = -xnapr;
                }
            }

А вот логика взаимодействия с ракеткой, потолком и полом:

//если сталкнулись с ракеткой
            if (((x + cx > this.Location.X) && (x < (this.Location.X + this.Width))) && ((y + cy > this.Location.Y) && (y + cy < (this.Location.Y + this.Height))))
                //то меняем направление по у
                ynapr = -ynapr;
            //если стокнулись с верней границей экрана
            if (y <= 1)
                //то меняем направление
                ynapr = -ynapr;
            //если дотронулись до нижнего края экрана, значит ракетка пропустила шарик
            if (y + cy > Screen.PrimaryScreen.Bounds.Height)
            {
               //останавливаем основную логику
                MainTimer.Stop();
                //останавлеваем отслеживание кол-во секунд игры
                Time.Stop();
                //выводим результаты
                MessageBox.Show("Вы продержались " + time.ToString() + " сек.", "Game Over");
                //ставим кнопку пуск на законное место
                SetParent(pusk, FindWindow("Shell_TrayWnd", null).ToInt32());
                ShowWindow(pusk, 5);
                //самоубийтсво :)
                Close();
            }

После всего этого, передвигаем пуск на новые координаты:

SetWindowPos(pusk, -1, x+=xplus*xnapr, y+=yplus*ynapr, cx, cy, 0x0040);

Осталось добавить отображение времени на нашей ракетки:

private void Time_Tick(object sender, EventArgs e)
        {
            time++;
            label1.Text= time.ToString();
        }

И добавить увеличение скорости:

private void Speed_Tick(object sender, EventArgs e)
        {
            xplus++;
            yplus++;
         }

GAME типа OVER
Вот и все, десять минут и можно замутить прикольную «гаму»:) Это конечно не халфлайфдва, но прикольная развлекуха в середине рабочего дня на полчасика обеспечена. Очень интересно играть с друзьями на время, посмотреть кто самый внимательный.
P.S. для тех, кто интересуется – самый большой рекорд 103 секунды, кто побьет, отпишитесь в комментариях.
P.P.S если после игры пуск не появился – просто вызовите диспетчер задач, или перезапустите эксплорер.