Здарова пацаны. В общем, обратился ко мне друг на днях, с просьбой написать ему игру(гонки) для шараги, почесал я репу и согласился, за символические 500 рублей сделать ему этот шедевр(за который он между прочим получил 2 пятерки). Потратил я на это: 2 кружки кофе(nescafe gold barista) 3 сижки(Philip Morris exotic mix) 3 часа своего не драгоценного времени Не знаю, кому это может потребоваться, но надеюсь кому-то пригодятся мои труды Ладно, хватит разглагольствовать, перейдем к тому как я это реализовал. 1. Создаем проект winForms 2. Создаем сразу несколько форм с меню, гаражом и собсна с игрой(Form1, garage, game) Главное меню Гараж Игра На форму с главным меню кидаем: 3 Кнопки (Играть, Гараж, Выход) Лэйбл с названием игры И переходим к коду. На кнопку выхода сразу вешаем: Application.Exit(); Код Application.Exit(); Думаю, объяснять что это значит не надо На кнопку "Гараж" вешаем функцию вызова формы с гаражом(у меня она называется garage): garage Garage = new garage(); Garage.Show(); Код garage Garage = new garage(); Garage.Show(); А, еще один момент, надо перейти в класс Program.cs и добавить туды переменную для хранения пути до выбранной машины. Код: public static class Info { public static string Car_model { get; set; } // переменная для хранения пути до картинки с машиной } Код public static class Info { public static string Car_model { get; set; } // переменная для хранения пути до картинки с машиной } Перейдем на форму с гаражом. На нее кидаем: лэйбл с надписью "Выбери машину:" 2 pictureBox'a с модельками машины(они будут в конце статьи), называем их car1 и car2 Два раза клиаем по обоим пиктуреБоксам, чтобы создать событие на клик по ним. В событие клика первого pictureBox'a пишем данный код: Info.Car_model = "res/car01.png"; // присвоение значения пути до первой модели машины(тут надо указать путь до картинки) DialogResult result = MessageBox.Show("Вы выбрали первую машину, покинуть гараж?", "Гараж", MessageBoxButtons.YesNo, MessageBoxIcon.Question); // вывод диалогового окна if (result == DialogResult.Yes) // если ответ да { this.Close(); // закрытие формы } Код Info.Car_model = "res/car01.png"; // присвоение значения пути до первой модели машины(тут надо указать путь до картинки) DialogResult result = MessageBox.Show("Вы выбрали первую машину, покинуть гараж?", "Гараж", MessageBoxButtons.YesNo, MessageBoxIcon.Question); // вывод диалогового окна if (result == DialogResult.Yes) // если ответ да { this.Close(); // закрытие формы } Второго: Info.Car_model = "res/car02.png"; // присвоение значения пути до второй модели машины DialogResult result = MessageBox.Show("Вы выбрали вторую машину, покинуть гараж?", "Гараж", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (result == DialogResult.Yes) { this.Close(); } Код Info.Car_model = "res/car02.png"; // присвоение значения пути до второй модели машины DialogResult result = MessageBox.Show("Вы выбрали вторую машину, покинуть гараж?", "Гараж", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (result == DialogResult.Yes) { this.Close(); } Переходим обратно на первую форму (которая с меню) и на событие клика кнопки играть вешаем это: if (Info.Car_model != null) // проверка переменной в которой хранится путь до картинки с машиной { game Game = new game(); Game.Show(); // Открытие формы с игрой this.Hide(); // Скрытие формы с меню, чтобы не мешала } else // если в ней нет значения { MessageBox.Show("Сначала выбери машину в гараже"); // выводим сообщение с ошибкой } Код if (Info.Car_model != null) // проверка переменной в которой хранится путь до картинки с машиной { game Game = new game(); Game.Show(); // Открытие формы с игрой this.Hide(); // Скрытие формы с меню, чтобы не мешала } else // если в ней нет значения { MessageBox.Show("Сначала выбери машину в гараже"); // выводим сообщение с ошибкой } Теперь открываем форму с игрой. В настройках формы, в поле BackgoundImage подгружаем картинку с дорогой (все ресурсы внизу). Кидаем три(3) pictureBox'a, и называем их player и enemy и finish на пиктуреБокс с финишем вешаем картинку с финишной полосой Так же на нее кидаем 6 таймеров, Interval ставим 10. Называем их так: Спойлер Кидаем Label, в котором пишем: и в поле name пишем Все, форму настроили, переходим к коду. Влетаем в него с ноги и сразу же добавляем либу Drawing: using System.Drawing; Код using System.Drawing; и пока форма в ахуе, объявляем переменные: Image player_img; // переменная с картинкой машины игрока int playerspeed = 10; // переменная со скоростью игрока int enemyspeed = 5; // переменная со скоростью противника bool pause = true; // переменная паузы Image enemy_img; // переменная с картинкой машины противника Random rnd = new Random(); // рандом Код Image player_img; // переменная с картинкой машины игрока int playerspeed = 10; // переменная со скоростью игрока int enemyspeed = 5; // переменная со скоростью противника bool pause = true; // переменная паузы Image enemy_img; // переменная с картинкой машины противника Random rnd = new Random(); // рандом Так, переменные объявили, теперь идем public game() и там пишем: player_img = new Bitmap(Info.Car_model); // берем из переменной Car_model путь до картинки с машиной player.Image = player_img; // присваиваем объекту player(pictureBox) картинку с машиной enemy_img = new Bitmap($"res/car0{rnd.Next(1, 5)}.png"); // выбираем рандомную картинку для машины противника enemy.Image = enemy_img; // присваиваем рандомную картинку объекту enemy Код player_img = new Bitmap(Info.Car_model); // берем из переменной Car_model путь до картинки с машиной player.Image = player_img; // присваиваем объекту player(pictureBox) картинку с машиной enemy_img = new Bitmap($"res/car0{rnd.Next(1, 5)}.png"); // выбираем рандомную картинку для машины противника enemy.Image = enemy_img; // присваиваем рандомную картинку объекту enemy Дальше прописываем код для каждого таймера: private void move_left_timer_Tick(object sender, EventArgs e) // таймер движения вперед (вправо) { if (player.Left < 1460) // проверка, чтобы игрок не заезжал за рамки трассы { player.Left += playerspeed; // Двигаем picuteBox с игроком } } private void move_up_timer_Tick(object sender, EventArgs e) // таймер движения влево (вверх) { if (player.Top > 210) // проверка, чтобы игрок не заезжал за рамки трассы { player.Top -= playerspeed; // Двигаем picuteBox с игроком } } private void move_down_timer_Tick(object sender, EventArgs e) // таймер движения вправо (вниз) { if (player.Top < 470) // проверка, чтобы игрок не заезжал за рамки трассы { player.Top += playerspeed; // Двигаем picuteBox с игроком } } private void enemy_move_timer_Tick(object sender, EventArgs e) { enemy.Left += enemyspeed + rnd.Next(2, 8); // движение противника, с рандомом } private void finish_timer_Tick(object sender, EventArgs e) // таймер проверки пересечения финиша или столкновения игрока с врагом { if (player.Bounds.IntersectsWith(finish.Bounds)) // проверка пересечения игрока линии финиша { move_right_timer.Stop(); // останавливаем таймер движения вперед(вправо) enemy_move_timer.Stop(); // останавливаем таймер движения противника pause = true; // ставим паузу pause_label.Text = "Поздравляю! Вы выиграли"; pause_label.Show(); // меняем надпись лэйбла и выводим его } if (enemy.Bounds.IntersectsWith(finish.Bounds)) // проверка пересечения врага линии финиша { enemy_move_timer.Stop(); pause = true; pause_label.Text = "Увы, но вы проиграли"; pause_label.Show(); } if (player.Bounds.IntersectsWith(enemy.Bounds)) // проверка столкновения игрока с врагом { enemy_move_timer.Stop(); pause = true; pause_label.Text = "Вы врезались, машина сломана"; pause_label.Show(); } } Код private void move_left_timer_Tick(object sender, EventArgs e) // таймер движения вперед (вправо) { if (player.Left < 1460) // проверка, чтобы игрок не заезжал за рамки трассы { player.Left += playerspeed; // Двигаем picuteBox с игроком } } private void move_up_timer_Tick(object sender, EventArgs e) // таймер движения влево (вверх) { if (player.Top > 210) // проверка, чтобы игрок не заезжал за рамки трассы { player.Top -= playerspeed; // Двигаем picuteBox с игроком } } private void move_down_timer_Tick(object sender, EventArgs e) // таймер движения вправо (вниз) { if (player.Top < 470) // проверка, чтобы игрок не заезжал за рамки трассы { player.Top += playerspeed; // Двигаем picuteBox с игроком } } private void enemy_move_timer_Tick(object sender, EventArgs e) { enemy.Left += enemyspeed + rnd.Next(2, 8); // движение противника, с рандомом } private void finish_timer_Tick(object sender, EventArgs e) // таймер проверки пересечения финиша или столкновения игрока с врагом { if (player.Bounds.IntersectsWith(finish.Bounds)) // проверка пересечения игрока линии финиша { move_right_timer.Stop(); // останавливаем таймер движения вперед(вправо) enemy_move_timer.Stop(); // останавливаем таймер движения противника pause = true; // ставим паузу pause_label.Text = "Поздравляю! Вы выиграли"; pause_label.Show(); // меняем надпись лэйбла и выводим его } if (enemy.Bounds.IntersectsWith(finish.Bounds)) // проверка пересечения врага линии финиша { enemy_move_timer.Stop(); pause = true; pause_label.Text = "Увы, но вы проиграли"; pause_label.Show(); } if (player.Bounds.IntersectsWith(enemy.Bounds)) // проверка столкновения игрока с врагом { enemy_move_timer.Stop(); pause = true; pause_label.Text = "Вы врезались, машина сломана"; pause_label.Show(); } } Переходим в конструктор формы, в настройках формы находим события KeyDown и KeyUp, нажимаем на них 2 раза Настройки формы В KeyDown Пишем обработчик нажатия клавиш: [CODE]if (e.KeyCode == Keys.Space) // если нажата клавиша Space { if (pause) //проверяем переменную pause, если истина то: { pause = false; // меняем на ложь pause_label.Hide(); //скрываем лэйбл паузы Thread.Sleep(1000); // задержка в одну секунду, чтобы игрок успел сориентироваться enemy_move_timer.Start(); // запускаем таймер с движением противника finish_timer.Start(); } else // если ложь, то: { pause = true; // меняем на истину pause_label.Show(); // показываем лэйбл паузы enemy_move_timer.Stop(); finish_timer.Stop(); } } if (!pause) // проверяем стоит ли игры на паузе, если нет то: { if (e.KeyCode == Keys.Up || e.KeyCode == Keys.W) // проверяем если нажата клавиша вверх или W { move_right_timer.Start(); // запускаем таймер движения вперед(вправо) } if (e.KeyCode == Keys.Left || e.KeyCode == Keys.A) // если нажата клавиша влево или A { move_up_timer.Start(); // запускаем таймер движения влево(вверх) } if (e.KeyCode == Keys.Right || e.KeyCode == Keys.D) // если нажата клавиша вправо или D { move_down_timer.Start(); // запускаем таймер движения вправо(вниз) } }[/CODE]В KeyUp это: [CODE] if (e.KeyCode == Keys.Up || e.KeyCode == Keys.W) // если отпущена клавиша вверх или W { move_right_timer.Stop(); // останавливаем таймер движения вперед(вправо) } if (e.KeyCode == Keys.Left || e.KeyCode == Keys.A) // если отпущена клавиша влево или A { move_up_timer.Stop(); // останавливаем таймер движения влево(вверх) } if (e.KeyCode == Keys.Right || e.KeyCode == Keys.D) // если отпущена клавиша вправо или D { move_down_timer.Stop(); // останавливаем таймер движения вправо(вниз) }[/CODE] Вот и вся игра, реализовал так, как додумался, возможно это можно сделать более элегантно. Ссылка на исходники + ресурсы: ссылОчка P.S. Прошу не бить за говнокод и за говностатью, извините опыта не много P.S.S. Если это кому-либо пригодится, напишите, мне будет очень приятно P.S.S.S. Код формы Form1 [CODE]using System; using System.Windows.Forms; namespace Gonki { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button3_Click(object sender, EventArgs e) { Application.Exit(); // Закрытие игры } private void Game_butt_Click(object sender, EventArgs e) { if (Info.Car_model != null) // проверка переменной в которой хранится путь до картинки с машиной { game Game = new game(); Game.Show(); // Открытие формы с игрой this.Hide(); // Скрытие формы с меню, чтобы не мешала } else // если в ней нет значения { MessageBox.Show("Сначала выбери машину в гараже"); // выводим сообщение с ошибкой } } private void Garage_butt_Click(object sender, EventArgs e) { garage Garage = new garage(); Garage.Show(); // Открытин формы с гаражом } private void Form1_Load(object sender, EventArgs e) { } private void Form1_FormClosed(object sender, FormClosedEventArgs e) { Application.Exit(); } } } [/CODE] Код формы garage [CODE]using System; using System.Windows.Forms; namespace Gonki { public partial class garage : Form { string caption = "Гараж"; public garage() { InitializeComponent(); } private void Car1_Click(object sender, EventArgs e) { car1_lab.Text = "Выбрано"; // Отображение надписи под выбранной машиной car2_lab.Text = ""; Info.Car_model = "res/car01.png"; // присвоение значения пути до первой модели машины DialogResult result = MessageBox.Show("Вы выбрали первую машину, покинуть гараж?", caption, MessageBoxButtons.YesNo, MessageBoxIcon.Question); // вывод диалогового окна if (result == DialogResult.Yes) // если ответ да { this.Close(); // закрытие формы } } private void Car2_Click(object sender, EventArgs e) { car2_lab.Text = "Выбрано"; car1_lab.Text = ""; Info.Car_model = "res/car02.png"; // присвоение значения пути до второй модели машины DialogResult result = MessageBox.Show("Вы выбрали вторую машину, покинуть гараж?", caption, MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (result == DialogResult.Yes) { this.Close(); } } } } [/CODE] Код класса Program.cs [CODE]using System; using System.Windows.Forms; namespace Gonki { static class Program { /// <summary> /// Главная точка входа для приложения. /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } } public static class Info { public static string Car_model { get; set; } // переменная для хранения пути до картинки с машиной } }[/CODE] Код формы game [CODE]using System; using System.Drawing; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace Gonki { public partial class game : Form { Image player_img; // переменная с картинкой машины игрока int playerspeed = 10; // переменная со скоростью игрока int enemyspeed = 5; // переменная со скоростью противника bool pause = true; // переменная паузы Image enemy_img; // переменная с картинкой машины противника Random rnd = new Random(); // рандом public game() { InitializeComponent(); player_img = new Bitmap(Info.Car_model); // берем из переменной Car_model путь до картинки с машиной player.Image = player_img; // присваеваем объекту player(pictureBox) картинку с машиной enemy_img = new Bitmap($"res/car0{rnd.Next(1, 5)}.png"); // выбираем рандомную картинку для машины противника enemy.Image = enemy_img; // присваиваем рандомную картинку объекту enemy } private void game_FormClosed(object sender, FormClosedEventArgs e) // если форма закрылась { Form1 form = new Form1(); form.Show(); // Отображение формы с меню } private void move_left_timer_Tick(object sender, EventArgs e) // таймер движения вперед (вправо) { if (player.Left < 1460) // проверка, чтобы игрок не заезжал за рамки трассы { player.Left += playerspeed; // Двигаем picuteBox с игроком } } private void move_up_timer_Tick(object sender, EventArgs e) // таймер движения влево (вверх) { if (player.Top > 210) // проверка, чтобы игрок не заезжал за рамки трассы { player.Top -= playerspeed; // Двигаем picuteBox с игроком } } private void move_down_timer_Tick(object sender, EventArgs e) // таймер движения вправо (вниз) { if (player.Top < 470) // проверка, чтобы игрок не заезжал за рамки трассы { player.Top += playerspeed; // Двигаем picuteBox с игроком } } private void game_KeyDown(object sender, KeyEventArgs e) // событие нажатия клавиши { if (e.KeyCode == Keys.Space) // если нажата клавиша Space { if (pause) //проверяем переменную pause, если истина то: { pause = false; // меняем на ложь pause_label.Hide(); //скрываем лэйбл паузы Thread.Sleep(1000); // задержка в одну секунду, чтобы игрок успел сориентироваться enemy_move_timer.Start(); // запускаем таймер с движением противника finish_timer.Start(); } else // если ложь, то: { pause = true; // меняем на истину pause_label.Show(); // показываем лэйбл паузы enemy_move_timer.Stop(); finish_timer.Stop(); } } if (!pause) // проверяем стоит ли игры на паузе, если нет то: { if (e.KeyCode == Keys.Up || e.KeyCode == Keys.W) // проверяем если нажата клавиша вверх или W { move_right_timer.Start(); // запускаем таймер движения вперед(вправо) } if (e.KeyCode == Keys.Left || e.KeyCode == Keys.A) // если нажата клавиша влево или A { move_up_timer.Start(); // запускаем таймер движения влево(вверх) } if (e.KeyCode == Keys.Right || e.KeyCode == Keys.D) // если нажата клавиша вправо или D { move_down_timer.Start(); // запускаем таймер движения вправо(вниз) } } } private void game_KeyUp(object sender, KeyEventArgs e) // событие отпускания клавиши { if (e.KeyCode == Keys.Up || e.KeyCode == Keys.W) // если нажата клавиша вверх или W { move_right_timer.Stop(); // останавливаем таймер движения вперед(вправо) } if (e.KeyCode == Keys.Left || e.KeyCode == Keys.A) // если нажата клавиша влево или A { move_up_timer.Stop(); // останавливаем таймер движения влево(вверх) } if (e.KeyCode == Keys.Right || e.KeyCode == Keys.D) // если нажата клавиша вправо или D { move_down_timer.Stop(); // останавливаем таймер движения вправо(вниз) } } private void enemy_move_timer_Tick(object sender, EventArgs e) { enemy.Left += enemyspeed + rnd.Next(2, 8); // движение противника, с рандомом } private void finish_timer_Tick(object sender, EventArgs e) // таймер проверки пересечения финиша или столкновения игрока с врагом { if (player.Bounds.IntersectsWith(finish.Bounds)) // проверка пересечения игрока линии финиша { move_right_timer.Stop(); // останавливаем таймер движения вперед(вправо) enemy_move_timer.Stop(); // останавливаем таймер движения противника pause = true; // ставим паузу pause_label.Text = "Поздравляю! Вы выиграли"; pause_label.Show(); // меняем надпись лэйбла и выводим его } if (enemy.Bounds.IntersectsWith(finish.Bounds)) // проверка пересечения врага линии финиша { enemy_move_timer.Stop(); pause = true; pause_label.Text = "Увы, но вы проиграли"; pause_label.Show(); } if (player.Bounds.IntersectsWith(enemy.Bounds)) // проверка столкновения игрока с врагом { enemy_move_timer.Stop(); pause = true; pause_label.Text = "Вы врезались, машина сломана"; pause_label.Show(); } } } } [/CODE]
У меня вопрос, а зачем 4 таймера?) Можно же все делать в одном. Таймер и так работает асинхронно.) Плюс поскольку это старое доброе WinForm, используйте UserControls, для интерфейса.) А так вроде по логике и организации проекта все более менее нормально.) Кстати залейте эту игру на GitHub.) Как раз будет положено начало вашему портфолио.)
itstranger, насчет таймеров хз почему именно так, но тогда мне ничего лучше в голову не пришло, а насчет гитхаба, да, давно хотел создать, добавлять туды свой говнокод
Выглядит суглумиративненько. Как для новичков - пример кода норм. Хоть WinForms от части мертв, но пища для ума отличная, лайк.