Как написать игру на c visual studio

Время на прочтение
6 мин

Количество просмотров 418K

Пишем игры на C++, Часть 2/3 — State-based программирование
Пишем игры на C++, Часть 3/3 — Классика жанра

Здравствуй, Хабрахабр!

На хабре не очень много уроков по созданию игр, почему бы не поддержать отечественных девелоперов?
Представляю вам свои уроки, которые учат создавать игры на C++ с использованием SDL!

Что нужно знать

  • Хотя бы начальные знания C++ (использовать будем Visual Studio)
  • Терпение

О чем эта часть?

  • Мы создадим каркас для всех игр, в качестве отрисовщика будем использовать SDL. Это библиотека для графики.

В следующих постах будет больше экшена, это лишь подготовка :)

Почему SDL?

Я выбрал эту библиотеку как наиболее легкую и быструю в освоении. Действительно, от первой прочитанной статьи по OpenGL или DirectX до стотысячного переиздания змейки пройдет немало времени.

Теперь можно стартовать.

1.1. Начало начал

Скачиваем SDL с официального сайта.
Создаем проект Win32 в Visual Studio, подключаем lib’ы и includ’ы SDL (если вы не умеете этого делать, то гугл вам в помощь!)

Также необходимо использовать многобайтную кодировку символов. Для этого идем в Проект->Свойства->Свойства конфигурации->Набор символов->Использовать многобайтную кодировку.

Создаем файл main.cpp

#include <Windows.h>

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
	return 0;
}

Пока что он ничего не делает.

Царь и бог каркаса — класс Game
Game.h

#ifndef _GAME_H_
#define _GAME_H_

class Game
{
private:
	bool run;

public:
	Game();
	int Execute();

	void Exit();
};

#endif

Game.cpp

#include "Game.h"

Game::Game()
{
	run = true;
}

int Game::Execute()
{
	while(run);
	return 0;
}

void Game::Exit()
{
	run = false;
}

Создаем файл Project.h, он нам очень пригодится в будущем

#ifndef _PROJECT_H_
#define _PROJECT_H_

#include <Windows.h>

#include "Game.h"

#endif

Изменяем main.cpp

#include "Project.h"

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
	Game game;
	return game.Execute();
}

Уже чуточку получше, но все равно как-то не густо.

1.2. Графика

Создаем аж 2 класса — Graphics для отрисовки графики и Image для отрисовки картинок

Graphics.h

#ifndef _GRAPHICS_H_
#define _GRAPHICS_H_

#include "Project.h"

#include "Image.h"
class Image;

class Graphics
{
private:
	SDL_Surface* Screen;

public:
	Graphics(int width, int height);

	Image* NewImage(char* file);
	Image* NewImage(char* file, int r, int g, int b);
	bool DrawImage(Image* img, int x, int y);
	bool DrawImage(Image* img, int x, int y, int startX, int startY, int endX, int endY);

	void Flip();
};

#endif

Image.h

#ifndef _IMAGE_H
#define _IMAGE_H

#include "Project.h"

class Image
{
private:
	SDL_Surface* surf;
public:
	friend class Graphics;

	int GetWidth();
	int GetHeight();
};

#endif

Изменяем Project.h

#ifndef _PROJECT_H_
#define _PROJECT_H_

#pragma comment(lib,"SDL.lib")

#include <Windows.h>
#include <SDL.h>

#include "Game.h"
#include "Graphics.h"
#include "Image.h"

#endif

SDL_Surface — класс из SDL для хранения информации об картинке
Рассмотрим Graphics
NewImage — есть 2 варианта загрузки картинки. Первый вариант просто грузит картинку, а второй после этого еще и дает прозрачность картинке. Если у нас красный фон в картинке, то вводим r=255,g=0,b=0
DrawImage — тоже 2 варианта отрисовки картинки. Первый рисует всю картинку целиком, второй только часть картинки. startX, startY — координаты начала части картинки. endX, endY — конечные координаты части картинки. Этот метод рисования применяется, если используются атласы картинок. Вот пример атласа:

image
(изображение взято из веб-ресурса interesnoe.info)

Рассмотрим Image
Он просто держит свой сурфейс и дает право доступа к своим закрытым членам классу Graphics, а он изменяет сурфейс.
По сути, это обертка над SDL_Surface. Также он дает размер картинки

Graphics.cpp

#include "Graphics.h"

Graphics::Graphics(int width, int height)
{
	SDL_Init(SDL_INIT_EVERYTHING);
	Screen = SDL_SetVideoMode(width,height,32,SDL_HWSURFACE|SDL_DOUBLEBUF);
}

Image* Graphics::NewImage(char* file)
{
	Image* image = new Image();
	image->surf = SDL_DisplayFormat(SDL_LoadBMP(file));

	return image;
}

Image* Graphics::NewImage(char* file, int r, int g, int b)
{
	Image* image = new Image();
	image->surf = SDL_DisplayFormat(SDL_LoadBMP(file));

	SDL_SetColorKey(image->surf, SDL_SRCCOLORKEY | SDL_RLEACCEL,
		SDL_MapRGB(image->surf->format, r, g, b));

	return image;
}

bool Graphics::DrawImage(Image* img, int x, int y)
{
	if(Screen == NULL || img->surf == NULL)
        return false;
 
    SDL_Rect Area;
    Area.x = x;
    Area.y = y;
 
    SDL_BlitSurface(img->surf, NULL, Screen, &Area);
 
	return true;
}

bool Graphics::DrawImage(Image* img, int x, int y, int startX, int startY, int endX, int endY)
{
	if(Screen == NULL || img->surf == NULL)
        return false;
 
    SDL_Rect Area;
    Area.x = x;
    Area.y = y;

    SDL_Rect SrcArea;
	SrcArea.x = startX;
	SrcArea.y = startY;
	SrcArea.w = endX;
	SrcArea.h = endY;

	SDL_BlitSurface(img->surf, &SrcArea, Screen, &Area);

	return true;
}

void Graphics::Flip()
{
	SDL_Flip(Screen);
	SDL_FillRect(Screen,NULL, 0x000000);
}

В конструкторе инициализируется SDL и создается экран.
Функция Flip должна вызываться каждый раз после отрисовки картинок, она представляет получившееся на экран и чистит экран в черный цвет для дальнешней отрисовки.
Остальные функции малоинтересны, рекомендую разобраться в них самому

Image.cpp

#include "Image.h"

int Image::GetWidth()
{
	return surf->w;
}

int Image::GetHeight()
{
	return surf->h;
}

Нет, вы все правильно делаете, этот файл и должен быть таким :)

Надо изменить Game.h, Game.cpp и main.cpp
Game.h

#ifndef _GAME_H_
#define _GAME_H_

#include "Project.h"
class Graphics;

class Game
{
private:
	bool run;

	Graphics* graphics;

public:
	Game();
	int Execute(int width, int height);

	void Exit();
};

#endif

Тут мы добавляем указатель на Graphics и в Execute добавляем размер экрана

Game.cpp

#include "Game.h"

Game::Game()
{
	run = true;
}

int Game::Execute(int width, int height)
{
	graphics = new Graphics(width,height);

	while(run);
	
	SDL_Quit();
	return 0;
}

void Game::Exit()
{
	run = false;
}

Ничего особенного, разве что не пропустите функцию SDL_Quit для очистки SDL

main.cpp

#include "Project.h"

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
	Game game;
	return game.Execute(500,350);
}

Тут мы создаем экран размером 500 на 350.

1.3. Ввод

Надо поработать со вводом с клавиатуры

Создаем Input.h

#ifndef _INPUT_H_
#define _INPUT_H_

#include "Project.h"

class Input
{
private:
	SDL_Event evt;

public:
    void Update();

	bool IsMouseButtonDown(byte key);
	bool IsMouseButtonUp(byte key);
	POINT GetButtonDownCoords();

	bool IsKeyDown(byte key);
	bool IsKeyUp(byte key);
	byte GetPressedKey();

	bool IsExit();
};

#endif

SDL_Event — класс какого-нибудь события, его мы держим в Input’е для того, чтобы не создавать объект этого класса каждый цикл
Ниже расположены методы, не представляющие особого интереса. Примечание: методы с окончанием Down вызываются, когда клавиша была нажата, а с окончанием Up — когда опущена.

Input.cpp

#include "Input.h"

void Input::Update()
{
	while(SDL_PollEvent(&evt));
}

bool Input::IsMouseButtonDown(byte key)
{
	if(evt.type == SDL_MOUSEBUTTONDOWN)
		if(evt.button.button == key)
			return true;
	return false;
}

bool Input::IsMouseButtonUp(byte key)
{
	if(evt.type == SDL_MOUSEBUTTONUP)
		if(evt.button.button == key)
			return true;
	return false;
}

POINT Input::GetButtonDownCoords()
{
	POINT point;
	point.x = evt.button.x;
	point.y = evt.button.y;

	return point;
}

bool Input::IsKeyDown(byte key)
{
	return (evt.type == SDL_KEYDOWN && evt.key.keysym.sym == key);
}

bool Input::IsKeyUp(byte key)
{
	return (evt.type == SDL_KEYUP && evt.key.keysym.sym == key);
}

byte Input::GetPressedKey()
{
	return evt.key.keysym.sym;
}

bool Input::IsExit()
{
	return (evt.type == SDL_QUIT);
}

Здесь мы обрабатываем наш объект событий в функции Update, а остальные функции просто проверяют тип события и его значения.

Изменяем теперь Game.h и Game.cpp

#ifndef _GAME_H_
#define _GAME_H_

#include "Project.h"

#include "Graphics.h"
class Graphics;
#include "Input.h"
class Input;

class Game
{
private:
	bool run;

	Graphics* graphics;
	Input* input;

public:
	Game();
	int Execute(int width, int height);

	Graphics* GetGraphics();
	Input* GetInput();

	void Exit();
};

#endif

Как видно, мы добавили указатель на Input и создали методы-возвращатели Graphics и Input

Game.cpp

#include "Game.h"

Game::Game()
{
	run = true;
}

int Game::Execute(int width, int height)
{
	graphics = new Graphics(width,height);
	input = new Input();

	while(run)
	{
		input->Update();
	}
	
	delete graphics;
	delete input;

	SDL_Quit();
	return 0;
}

Graphics* Game::GetGraphics()
{
	return graphics;
}

Input* Game::GetInput()
{
	return input;
}

void Game::Exit()
{
	run = false;
}

1.4. Итоги

Это был первый урок. Если вы дошли до этого места, я вас поздравляю! У вас есть воля, присущая программисту :) Смотрите ссылки в начале статьи на последующие уроки для того, чтобы узнать еще много нового!

По всем вопросам обращайтесь в ЛС, а если вам не повезло быть зарегистрированным на хабре, пишите на мейл izarizar@mail.ru

Introduction: Make a Game Using Visual Studio

Hey Guys, its true. You can create your own game with basic knowledge of Visual Studio and C#. Before getting started I want to say that if you like this instructable then please VOTE ME for CODED-Creations Contest, by just clicking the VOTE option on the top right side of this instructable.

SOFTWARE Requirements :

1. Windows Vista/7/8/8.1

2. Visual Studio

SKILL Requirements :

1. Basic Knowledge of C/C++ and C#.

Here is a video if you want you can watch it.

WATCH HERE: [ PLAY VIDEO ]

Please Follow the steps carefully.

Step 1: Getting Started

1. Click FILE -> New Project.

2. Give project a name like «Tic Tac Toe » or of your choice.

3. You would see a basic dialog open with the title «Form 1».

4. In «Properties» dialog , there is a property called «Show Icon» .If you want you can remove the icon by toggling it from ‘TRUE’ to ‘FALSE’.

And if you want to change the form name click on ‘TEXT’ option and change the form name as desired.

5. In ‘ToolBox’ dialog there is a tool named as «MenuStrip». Just drag it to the form.

6. For basics create two menus as ‘Files’ and ‘Help’. Just type in the empty box that says «Type here». (Note :: we just named it and the menus are not functional, we need to proceed further for it ).

Click on ‘File'(in the form) and add sub menus as «New game» and «Exit». And in Help add a sub-menu named » About»

Step 2: Adding a Game Area

1. In ‘ToolBox’ dialog, there is a tool named «Button» just drag it to the form. Since its «Tic Tac Toe» it will have nine buttons. Drag it nine times and re-size it and adjust it accordingly.

2. After completely adjusting the work-space. Click on anyone of the button(tool) . And in ‘Property’ dialog adjust the Font , Big enough such that ‘X’ and ‘O’ s will be clearly visible. Make sure each button have same font.

3. Renameeach button in Matrix form(like : Button1 will become A1, Button2 = A2 ,Button3 = A3, Button4 = B1, Button5 = B2,Button6 = B3,Button7 = C1 , Button8 = C2 and Button9 =C3 where A,B,C are rows and 1,2,3 are Columns. )

This renaming will help us a lot in further process.

Step 3: Giving Tasks to the Menus

1. Click -> ‘Help'(in the form) and double click -> ‘About’.

2. Now a basic C# program will appear.

3. In ‘private void aboutToolStripMenu……. ‘ type

         MessageBox.Show("By //Your name//" , " Tic Tac Toe About ");

When you type MessageBox.Show( It will show a set of «21» string options. Make sure select the 3rd.(See the above image for more clarity) .

4. Similarly we would add a task for the //Exit// menu.

In ‘private void exitToolStripMenu…… ‘ type

          Application.Exit(); 

( see the images for more clarity)

5. Now similarly like «About» and «Exit» double click «New Game». In » private newGameTool………. » Tyep this code:

           turn = ture;<br>           turn_count = 0;<br>           try<br>           {<br>              foreach(Control c in Controls)<br>              {<br>                  Button b = (Button)c;<br>                  b.Enabled = true;<br>                  b.Text = "";<br>               }<br>            }<br>            catch { }<br>       

Step 4: Working on the

1. Go to the program and under » public partial class » Type ==>>

bool turn = true ;<br>int turn_count = 0;

(click on the image for ore clarity.)

2. In the form click on anyone of the button. In the «Properties» there is a «Thunder Bolt» Icon, click on it.

Under the «Click» property type this :: » button_click «.

Do this to all the 9 buttons. (Click on the second image for more clarity).

3. Write this code under » public partial class » …Type this===>>

private void button_click(object sender , EventArgs e)<br>{<br>  Button b = (Button)sender;<br>  if(turn)<br>    b.Text = "X";<br>  else<br>    b.Text = "O";<br>  turn = !turn;<br>  b.Enabled = false;<br>  turn_count++;<br>  check();<br>}

(Click on the images for more clarity).

Step 5: Checking the Winner

Our

main aim in this step is to check the winner. So we need to create a new class here. So basically the renaming of the button will be useful here.

1. Under » public partial class » type this===>>

private void check()
{ bool winner = false; //Horizontal checking if((A1.Text==A2.Text)&&(A2.Text==A3.Text)&&(!A1.Enabled)) winner = true; else if((B1.Text==B2.Text)&&(B2.Text==B3.Text)&&(!B1.Enabled)) winner = true; else if((C1.Text==C2.Text)&&(C2.Text==C3.Text)&&(!C1.Enabled)) winner = true; //Vertical Checking else if((A1.Text==B1.Text)&&(B1.Text==C1.Text)&&(!A1.Enabled)) winner = true; else if((A2.Text==B2.Text)&&(B2.Text==C2.Text)&&(!A2.Enabled)) winner = true; else if((A3.Text==B3.Text)&&(B3.Text==C3.Text)&&(!A3.Enabled)) winner = true; //Oblique Checking else if((A1.Text==B2.Text)&&(B2.Text==C3.Text)&&(!A1.Enabled)) winner = true; else if((A3.Text==B2.Text)&&(B2.Text==C1.Text)&&(!A3.Enabled)) winner = true;

if(winner) { disableButtons(); String win = ""; if(turn) win = "O"; else win = "X"; MessageBox.Show(win + " Wins ! " , "Yay"); // Click Image for more clarity(string operation 2/21) } else { if(turn_count == 9) MessageBox.Show("Draw !","Bummer"); } }//End of class

2. Now we have to disable the buttons as soon as

someone wins

create a new class under » public partial class » Type this==>>

private void disableButtons()
{

try

{

foreach(Control c in Controls)

{

Button b = (Button)c;

b.Enabled = false;

}

}

catch { }

}

Step 6: Step 6 : Enjoy the Game

CONGRATULATIONS !

You have completed creating your own «Tic Tac Toe» game . Enjoy playing your game.

If you liked this instructable please do VOTE me for the Contest.

And there are some videos to do add-on s if want you can watch them.

THANK YOU VIEWING THIS INSTRUCTABLE

Be the First to Share

Recommendations

Introduction: Make a Game Using Visual Studio

Hey Guys, its true. You can create your own game with basic knowledge of Visual Studio and C#. Before getting started I want to say that if you like this instructable then please VOTE ME for CODED-Creations Contest, by just clicking the VOTE option on the top right side of this instructable.

SOFTWARE Requirements :

1. Windows Vista/7/8/8.1

2. Visual Studio

SKILL Requirements :

1. Basic Knowledge of C/C++ and C#.

Here is a video if you want you can watch it.

WATCH HERE: [ PLAY VIDEO ]

Please Follow the steps carefully.

Step 1: Getting Started

1. Click FILE -> New Project.

2. Give project a name like «Tic Tac Toe » or of your choice.

3. You would see a basic dialog open with the title «Form 1».

4. In «Properties» dialog , there is a property called «Show Icon» .If you want you can remove the icon by toggling it from ‘TRUE’ to ‘FALSE’.

And if you want to change the form name click on ‘TEXT’ option and change the form name as desired.

5. In ‘ToolBox’ dialog there is a tool named as «MenuStrip». Just drag it to the form.

6. For basics create two menus as ‘Files’ and ‘Help’. Just type in the empty box that says «Type here». (Note :: we just named it and the menus are not functional, we need to proceed further for it ).

Click on ‘File'(in the form) and add sub menus as «New game» and «Exit». And in Help add a sub-menu named » About»

Step 2: Adding a Game Area

1. In ‘ToolBox’ dialog, there is a tool named «Button» just drag it to the form. Since its «Tic Tac Toe» it will have nine buttons. Drag it nine times and re-size it and adjust it accordingly.

2. After completely adjusting the work-space. Click on anyone of the button(tool) . And in ‘Property’ dialog adjust the Font , Big enough such that ‘X’ and ‘O’ s will be clearly visible. Make sure each button have same font.

3. Renameeach button in Matrix form(like : Button1 will become A1, Button2 = A2 ,Button3 = A3, Button4 = B1, Button5 = B2,Button6 = B3,Button7 = C1 , Button8 = C2 and Button9 =C3 where A,B,C are rows and 1,2,3 are Columns. )

This renaming will help us a lot in further process.

Step 3: Giving Tasks to the Menus

1. Click -> ‘Help'(in the form) and double click -> ‘About’.

2. Now a basic C# program will appear.

3. In ‘private void aboutToolStripMenu……. ‘ type

         MessageBox.Show("By //Your name//" , " Tic Tac Toe About ");

When you type MessageBox.Show( It will show a set of «21» string options. Make sure select the 3rd.(See the above image for more clarity) .

4. Similarly we would add a task for the //Exit// menu.

In ‘private void exitToolStripMenu…… ‘ type

          Application.Exit(); 

( see the images for more clarity)

5. Now similarly like «About» and «Exit» double click «New Game». In » private newGameTool………. » Tyep this code:

           turn = ture;<br>           turn_count = 0;<br>           try<br>           {<br>              foreach(Control c in Controls)<br>              {<br>                  Button b = (Button)c;<br>                  b.Enabled = true;<br>                  b.Text = "";<br>               }<br>            }<br>            catch { }<br>       

Step 4: Working on the

1. Go to the program and under » public partial class » Type ==>>

bool turn = true ;<br>int turn_count = 0;

(click on the image for ore clarity.)

2. In the form click on anyone of the button. In the «Properties» there is a «Thunder Bolt» Icon, click on it.

Under the «Click» property type this :: » button_click «.

Do this to all the 9 buttons. (Click on the second image for more clarity).

3. Write this code under » public partial class » …Type this===>>

private void button_click(object sender , EventArgs e)<br>{<br>  Button b = (Button)sender;<br>  if(turn)<br>    b.Text = "X";<br>  else<br>    b.Text = "O";<br>  turn = !turn;<br>  b.Enabled = false;<br>  turn_count++;<br>  check();<br>}

(Click on the images for more clarity).

Step 5: Checking the Winner

Our

main aim in this step is to check the winner. So we need to create a new class here. So basically the renaming of the button will be useful here.

1. Under » public partial class » type this===>>

private void check()
{ bool winner = false; //Horizontal checking if((A1.Text==A2.Text)&&(A2.Text==A3.Text)&&(!A1.Enabled)) winner = true; else if((B1.Text==B2.Text)&&(B2.Text==B3.Text)&&(!B1.Enabled)) winner = true; else if((C1.Text==C2.Text)&&(C2.Text==C3.Text)&&(!C1.Enabled)) winner = true; //Vertical Checking else if((A1.Text==B1.Text)&&(B1.Text==C1.Text)&&(!A1.Enabled)) winner = true; else if((A2.Text==B2.Text)&&(B2.Text==C2.Text)&&(!A2.Enabled)) winner = true; else if((A3.Text==B3.Text)&&(B3.Text==C3.Text)&&(!A3.Enabled)) winner = true; //Oblique Checking else if((A1.Text==B2.Text)&&(B2.Text==C3.Text)&&(!A1.Enabled)) winner = true; else if((A3.Text==B2.Text)&&(B2.Text==C1.Text)&&(!A3.Enabled)) winner = true;

if(winner) { disableButtons(); String win = ""; if(turn) win = "O"; else win = "X"; MessageBox.Show(win + " Wins ! " , "Yay"); // Click Image for more clarity(string operation 2/21) } else { if(turn_count == 9) MessageBox.Show("Draw !","Bummer"); } }//End of class

2. Now we have to disable the buttons as soon as

someone wins

create a new class under » public partial class » Type this==>>

private void disableButtons()
{

try

{

foreach(Control c in Controls)

{

Button b = (Button)c;

b.Enabled = false;

}

}

catch { }

}

Step 6: Step 6 : Enjoy the Game

CONGRATULATIONS !

You have completed creating your own «Tic Tac Toe» game . Enjoy playing your game.

If you liked this instructable please do VOTE me for the Contest.

And there are some videos to do add-on s if want you can watch them.

THANK YOU VIEWING THIS INSTRUCTABLE

Be the First to Share

Recommendations

Итак, вы уже готовы (идейно и технически) к созданию игры с использованием 2D-графики и идей объектно-ориентированного программирования в среде Visual Studio C#. Начнем с создания достаточно простого шутера «Вторжение НЛО» («UFO Invasion»),  в котором придется отражать нашествие на Землю армады НЛО. Дальнейшее ее развитие вы сможете выполнить самостоятельно.

Проектирование шутера начинается с разработки сценария, после чего определяются классы (поля и методы), проектируется визуальный интерфейс игры, программируются методы этих классов.

Возможный сценарий игры

Действующие персонажи:  1) противник (враги — Enemies); 2) НЛО (один из видов противника — Bugs-«жучки»), ограничимся пока одним видом врагов; 3) защитник Земли  (игрок — Player).

Место действия. Сражение происходит в космическом пространстве в окрестностях Земли.

Противник. НЛО имеют традиционную форму тарелок, каждая из них отличается размерами и окраской. Над Землей они появляются сериями и планируют сверху вниз на Землю с различной скоростью, при этом возможно и их горизонтальное смещение. Интервал времени между появлениями серий может  уменьшаться. Количество НЛО в небе одновременно не превышает некоторого максимального числа — количество НЛО в космическом флоте противника.

Игрок. Игрок, находясь в своем корабле, использует свое оружие с лазерным прицелом (blaster) и перемещается в околоземном пространстве, старается сбить НЛО противника. Для управления перемещением игрока используется мышь, стрельба — нажатием левой кнопки мыши.

 Взаимодействие. При попадании в НЛО следует обозначить его подрыв и удалить его останки из околоземного пространства. В первом приближении будем считать, что физическое касание НЛО и корабля не приводит к потере корабля игрока (это будет следующая задача).

Цель игры — уничтожить максимальное количество НЛО противника (максимальный результат — 100%).

Проектирование классов

Обозначив в сценарии сущности, мы определим три класса:
1) Enemies — противник;
2) Bugs — НЛО;
3) Player – игрок.
Автоматически создается класс
4) Form1 – форма.
Нам еще пригодится вспомогательный класс
5) BrushColor – кисти/цвета.

Класс Player

Поля класса:
public Point point;              // положение игрока в 2D-пространстве
public Size size;                   // размеры игрока
public Region reg;               // занимаемая им область в пространстве
public Pen laser_pen;        // свойство оружия
Методы класса:
public void New_player()          // задать свойства (параметры) игрока
public void Show_player()        // показать его на поле  битвы
Содержание методов этого и последующих классов рассмотрим позднее.

Класс Bugs

Поля:
public Point point;                // положение НЛО в 2D-пространстве
public Size size;                     // размеры НЛО
int veloX;                                  // скорость смещения по X
int veloY;                                  // скорость_падения по Y
public HatchBrush br;        // кисть для покраски НЛО
public Region reg = new Region();   // занимаемая им область в пространстве
public Boolean life = true;                  // НЛО жив (true) или мертв (false)
Методы:
public void New_bug()            // задать свойства (параметры) НЛО
public void Form_bug()           // задать форму НЛО, например, тарелку
public void Move_bug()           // задать новое местоположение НЛО

Класс Enemies

Поля:
а)  для генерации серий
public int Delta_N;                // количество НЛО в серии
public int N_generation;     // число генераций — серий
public int k_generation;     // номер серии
public int N;                            // актуальное количество НЛО на экране
б)  массив  НЛО-объектов
public Bugs[] bugs = new Bugs[Form1.N_max];
Примечание. Поле N_max задается константой в классе Form1 (см. ниже), а последнее поле bugs  задает массив ссылок на объекты-НЛО.
Методы:
public void New_Enemies()     // инициализация объектов НЛО
public void Show_bugs()          // сдвинуть и показать «живые» НЛО
public void Enemy()                   // генерация одной серии НЛО
public void Killed_bugs()          // определение сбитых НЛО
public int Select_bugs()             // удаление сбитых НЛО

Вспомогательный класс BrushColor

Поля класса:
public Color FonColor;             // цвет фона
public Color LaserColor;         // цвет лазера
public Color DashBug;             // цвет штриховки НЛО
public Color KilledBug;            // цвет сбитого НЛО
Методы класса:
public BrushColor()                                   // конструктор  (настройка цветов)
public HatchBrush New_br(int rch)   // кисть для задания цвета НЛО
public Color RandomColor(int rch)     // генератор случайного цвета

Класс Form1

Поля:
public const int N_max = 200;    // Максимальное количество НЛО на экране
public Player player = new Player();     // Игрок, который сбивает НЛО (объект)
public Boolean laser = false;                    // Его оружие — бластер
public Bitmap imageP;                               //  Изображения игрока
public int Result = 0;                                   // Количество сбитых НЛО (счет игры)
public Graphics g;                                       // холст для битвы
public BrushColor bc= new BrushColor();       // набор кистей и цветов
public Enemies nlo = new Enemies();                // Все НЛО
Как мы видим, задана всего одна константа (необходима для определения размерности массива ссылок, см. класс  Enemies); три объекта классов Player, Enemies и BrushColor; поле laser (включен/выключен); поле imageP для хранения изображения игрока; поле Result для ведения счета подбитых НЛО; поле g — холст (графический контекст) для рисования.

Управление игрой. Выберем на панели элементов 4 визуальных объекта: три кнопки — button1 («Старт»), button2 («Лазер: включить/выключить»), button3 («Стоп») и textBox1 для отображения счета игры (Result) и перенесем их на форму. Также добавим 3 невизуальных объекта: timer1, timer2 и imageList1. Объект imageList1 будем использовать для хранения изображений игрока (player). Таймер timer1 будет задавать частоту изменений (минимальный временной такт). Таймер timer2 будем использовать для генерации  серий НЛО. Активность игрока свяжем, как указано в сценарии, с нажатием левой кнопки мыши и перемещением ее по экрану — событие MouseClick.

Методы класса  Form1 (реакции на события):
а) конструктор формы
public Form1()
б) при загрузке формы
private void Form1_Load(object sender, EventArgs e)
в) старт игры
private void button1_Click(object sender, EventArgs e)
г) включение/отключение лазера
private void button2_Click(object sender, EventArgs e)
д) стоп игры, результат
private void button3_Click(object sender, EventArgs e)
е)  один временной такт игры
private void timer1_Tick(object sender, EventArgs e)
ж) генерация серий
private void timer2_Tick(object sender, EventArgs e)
3) попадание НЛО под вертикальный обстрел лазером
private void Form1_MouseClick(object sender, MouseEventArgs e)

Настройка объектов

Для использования полного экрана зададим свойство Form1.WindowState=Maximized.

Подготовим в графическом редакторе изображения игрока размером 100х100 пикселей с именами player.bmp и player1.bmp, например так:

player12и сохраним их в папке Resourсes проекта. Зададим свойство imageList1.ImageSize = 100;100  и внесем в коллекцию imageList1.Images эти два файла (члены 0 и 1)

Зададим button3.Enabled=false.

Изображения НЛО будет генерировать метод public void Form_bug().

Настройки таймеров:
timer1.Enable=false (выключен);
timer2.Enable=false (выключен);
timer1.Interval=400 (0,4c);
timer2.interval=5000 (5c).

Исходный вид формы (в том числе с не визуальными компонентами) представлен ниже:

форма59

Вместо кнопок можно задать меню из трех позиций: Старт, Лазер, Стоп. Соответственно сменятся и названия методов, связанных с выбором пунктов меню.

Реализация методов класса Player:

а) Новый игрок

public void New_player(Form1 F)  
{
   size = F.imageP.Size;
   point.X = 0;
   point.Y = 0;
   Rectangle rec = new Rectangle(point, size);
   reg = new Region(rec);
   laser_pen = new Pen(new HatchBrush(HatchStyle.DashedUpwardDiagonal,
   F.bc.LaserColor, F.bc.LaserColor), 3);
}

Комментарии: Размер изображения определяется через размер рисунка (см. далее метод Form1_Load() ). Левый верхний угол объекта имеет координаты (0,0). Область, занимаемая игроком, прямоугольная. Цвет луча лазера определяется свойством  F.bc.LaserColor. Для доступа к объекту bc, расположенному на форме, параметр метода задаем как  Form1 F.

б) показать игрока

public void Show_player(Form1 F, int x, int y)
{
   F.g.ResetClip();
   F.g.FillRegion(new SolidBrush(F.BackColor), reg);
   point.X = x - size.Width / 2;
   point.Y = y;
   Rectangle rec = new Rectangle(point, size);
   reg = new Region(rec);
   F.g.DrawImage(F.imageP, point);
   F.g.ExcludeClip(reg);
}

Комментарии: Метод имеет параметры:  Form1 F (для доступа к объекту g и свойству BackColor – цвету фона), int x, int y — новые координаты игрока (x – ось симметрии). Первый оператор снимает защиту с предыдущей области расположения игрока. Также определяется новая область reg. Метод DrawImage(F.imageP, point) обеспечивает рисование игрока, метод ExcludeClip(reg) обеспечивает защиту заданной области до следующего вызова метода. Совет: Уберите первый и последний операторы и посмотрите на изменения в отображении игрока.

Реализация методов класса Bugs

а) генерация одного НЛО

public void New_bug(Form1 F, int rch)
{
   Random rv = new Random(rch);
   point.X = rv.Next(10, Form1.ActiveForm.Width - 40);
   point.Y = rv.Next(10, Form1.ActiveForm.Height / 5);
   size.Width = rv.Next(20,50);
   size.Height = size.Width * 2 / 3;
   veloX = rv.Next(7) - 3;
   veloY = rv.Next(3, 10);
   br = F.bc.New_br(rch);
   reg = Form_bug();
}

Комментарии: Метод формирует начальные координаты НЛО, его размеры, скорости смещения за 1 такт срабатывания таймера timer1, выбирает цвет кисти для его покраски. Везде используется генератор случайных чисел класса Random. Для задания области reg вызывается следующий метод.

б)  задание формы НЛО

public Region Form_bug()
{
   Point pt = new Point();
   Size st = new Size();
   pt.X = point.X;
   pt.Y = point.Y+size.Height/4;
   st.Width = size.Width;
   st.Height=size.Height/2;
   Rectangle rec = new Rectangle(pt, st);
   GraphicsPath path1 = new GraphicsPath();
   path1.AddEllipse(rec);
   Region reg= new Region(path1);
   rec.X = point.X + size.Width / 4;
   rec.Y = point.Y;
   rec.Width = size.Width / 2;
   rec.Height = size.Height;
   path1.AddEllipse(rec);
   reg.Union(path1);
   return reg;
}

Комментарий: Отметим использование объекта класса GraphicsPath и метода reg.Union(path1) — объединение двух эллипсов.

в) вертикальное падение НЛО с горизонтальными смещениями

public void Move_bug()
{
   point.X += veloX;
   point.Y += veloY;
   reg = Form_bug();
}

Комментарий: новая область размещения НЛО заполняется на каждом такте срабатывания таймера 1 после изменения координат через метод Form_bug().

Реализация методов класса Enemies

а) настройка серий и создание ссылок на объекты НЛО

public void New_Enemies(Form1 F)
{
   N_generation = 10;
   Delta_N = Form1.N_max / N_generation;
   k_generation = 0;
   N = 0;
   for (int j = 0; j < Form1.N_max; j++)
      bugs[j] = new Bugs();
}

Комментарии: В методе задается жестко число серий — 10. Вычисляется число НЛО в каждой серии. Обнуляется счетчик числа генераций (серий) и числа активных НЛО. Создаются ссылки на максимально возможное число объектов.

б) удаление сбитых НЛО

public int Select_bugs()
{
   int k = 0;
   for (int j = 0; j < N; j++)
   {
      if (!bugs[j].life)
         k++;
   }
   for (int i = 0; i < k; i++)
   {
      for (int j = 0; j < N; j++)
      {
         if (!bugs[j].life)
         {
            for (int j1 = j; j1 < (N - 1); j1++)
               bugs[j1] = bugs[j1 + 1];
            break;
         }
      }
      N--;
   }
   return k;    // счетчик подбитых НЛО
}

Комментарии: Если в результате попадания НЛО под луч лазера его свойство life=false, то такой объект удаляется из массива bugs. Сначала определяется общее количество подбитых НЛО, затем в цикле они по очереди удаляются путем сдвига. Количество  активных НЛО N также уменьшается. Метод возвращает k — число сбитых НЛО на данном такте.

в) смещение и отображение НЛО

public void Show_bugs(Form1 F)
{
   for (int j = 0; j < N; j++)
   {
      bugs[j].Move_bug();
      F.g.FillRegion(bugs[j].br, bugs[j].reg);
   }
}

Комментарий: Метод в цикле для активных НЛО обеспечивает их смещение и отображение на экране.

г) одна серия НЛО

public void Enemy(Form1 F)
{
   int N0 = N;
   N = N + Delta_N;
   int rch;
   Random rnd = new Random();
   for (int j = N0; j < N; j++)
   {
      bugs[j] = new Bugs();
      rch = rnd.Next();
      bugs[j].New_bug(F,rch);
      F.g.FillRegion(bugs[j].br, bugs[j].reg);
   }
}

Комментарий: Метод добавляет новую серию НЛО, каждый из которых имеет свой цвет, размеры и начальное местоположение.

д) подбитые НЛО, выделены F.bc.KilledBug цветом

public void Killed_bugs(Form1 F, int x, int y)
{
   for (int j = 0; j < N; j++)
   {
      Rectangle r = new Rectangle(x - bugs[j].size.Width / 2, 0, bugs[j].size.Width, y);
      if (bugs[j].reg.IsVisible(r, F.g) & F.laser)
      {
         bugs[j].br = new HatchBrush(HatchStyle.DarkHorizontal, F.bc.KilledBug, F.bc.KilledBug);
         F.g.FillRegion(bugs[j].br, bugs[j].reg);
         bugs[j].life = false;
      }
   }
}

Комментарий:  проверяет попадание объектов под лазерный прицел, отмечает их в свойстве life как false, обеспечивает вспышку НЛО при подрыве.

Реализация методов класса BrushColor

а) кисть для задания цвета НЛО

public HatchBrush New_br(int rch)
{
   return new HatchBrush (HatchStyle.DashedUpwardDiagonal, DashBug, RandomColor(rch));
}

Комментарий: Метод возвращает кисть класса HatchBrush (шаблон штриховки) из библиотеки System.Drawing.Drawing2D, состоит из одного оператора.

б)  случайный цвет

public Color RandomColor(int rch)      // rch - случайное число
{
   int r, g, b;
   byte[] bytes1 = new byte[3];        // массив 3 цветов
   Random rnd1 = new Random(rch);
   rnd1.NextBytes(bytes1);             // генерация в массив
   r = Convert.ToInt16(bytes1[0]);
   g = Convert.ToInt16(bytes1[1]);
   b = Convert.ToInt16(bytes1[2]);
   return Color.FromArgb(r, g, b);     // возврат цвета
}

Комментарий: этот метод мы уже использовали ранее в других примерах.

 Реализация методов класса Form1

а)  конструктор формы

public Form1()
{
   InitializeComponent();
}

Комментарий: без изменений.

б)  при загрузке формы

private void Form1_Load(object sender, EventArgs e)
{
   g = this.CreateGraphics();          // инициализация холста
   BackColor = bc.FonColor;            // цвет фона
   imageP = new Bitmap(imageList1.Images[0], 100, 100);
   player.New_player(this);            // инициализация игрока
   nlo = new Enemies();                // инициализация противника
   nlo.New_Enemies(this);              // инициализация НЛО как объектов
}

Комментарии: При загрузке формы задается холст, цвет фона, изображение игрока (прямоугольная область — первое изображение из коллекции  imageList1.Images[ ]), инициализируются объекты imageP, player, nlo (все НЛО).

в) Старт игры

private void button1_Click(object sender, EventArgs e)
{
   nlo.k_generation = 0;
   nlo.Enemy(this);
   timer1.Start();
   timer2.Start();
   button3.Enabled = true;
   button1.Enabled = false;
}

Комментарии: Номер первой серии = 0. Генерация первой серии НЛО — nlo.Enemy(this). Запуск таймеров. Открыть доступ к кнопке «Стоп», закрыть доступ к кнопке «Старт».

г) Включение/отключение лазера игроком

private void button2_Click(object sender, EventArgs e)
{
   if (laser)
   {
      laser = false;
      button2.Text = "Включить Лазер";
   }
   else
   {
      laser = true;
      button2.Text = "Отключить Лазер";
   }
}

Комментарий: включение/отключение лазера игроком

д) Стоп. Результат

private void button3_Click(object sender, EventArgs e)
{
   timer1.Stop();
   timer2.Stop();
   imageP = new Bitmap(imageList1.Images[1], 100, 100);
   int procent = Result * 100 / (nlo.Delta_N * nlo.N_generation);
   string msg = "Подбито " + Result.ToString() + " НЛО, " + procent.ToString() + "% результат";
   MessageBox.Show(msg, "Ваш результат", MessageBoxButtons.OK);
   player.Show_player(this, 50, 50);
   nlo.N = 0;
   button1.Enabled = true;
   Result = 0;
   textBox1.Text = Result.ToString();
}

Комментарии: Остановка таймеров (игры). Помещение игрока в «гараж»  (на красном фоне, вывод второго изображения из коллекции  imageList1.Images[]), расчет результата игры в процентах, его вывод в окне  MessageBox, обнуление числа активных объектов НЛО, открытие доступа к кнопке «Старт», обнуление результата. Игра снова может быть запущена без перезапуска приложения.

е) один временной такт

private void timer1_Tick(object sender, EventArgs e)
{
   g.Clear(BackColor);
   Result = Result + nlo.Select_bugs();
   nlo.Show_bugs(this);
   textBox1.Text = Result.ToString();
}

Комментарии: При срабатывании 1-го таймера производится очистка фона кроме защищенной области под игроком (см. выше метод Show_player(Form1 F, int x, int y)), что позволяет избежать исчезновения игрока. К результату добавляется число сбитых на предыдущем такте НЛО. Отображаются активные (ещё «живые») НЛО и текущий счет игры.

ж) генерация серий

private void timer2_Tick(object sender, EventArgs e)
{
   nlo.k_generation++;
   timer2.Interval -= 100;
   if (nlo.k_generation < nlo.N_generation)
      nlo.Enemy(this);
   else
   timer2.Stop();
 }

Комментарии: Увеличение номера серии на 1, сокращение на 100 мс интервала выпуска следующей серии, если реализованы все  nlo.N_generation, то остановка генерации ( timer2.Stop();) , иначе генерация очередной серии.

з)  попадание НЛО под вертикальный обстрел лазером

private void Form1_MouseClick(object sender, MouseEventArgs e)
{
   player.Show_player(this, e.X, e.Y);
   if (laser)
      g.DrawLine(player.laser_pen, player.point.X + player.size.Width / 2, player.point.Y, player.point.X + player.size.Width / 2, 0);
   nlo.Killed_bugs(this,e.X, e.Y);
}

Комментарии: И, наконец, последний самый главный метод, вызываемый при клике на форме, обеспечивает показ игрока в заданном мышью положении, выстрел из оружия, отметка подбитых НЛО, вспышки при их подрыве.

Интересно, что событие MouseClick демонстрирует взаимодействие объектов трех классов: Form1, Player и Enemies, а опосредовано и всех пяти (+ Bugs и BrushColor).

 На видео показан фрагмент  игры  «Вторжение НЛО».

Развитие игры

Опираясь на пример игры, постарайтесь ее развить.

Например, чтобы столкновение игрока с НЛО приводило к уменьшению счета игры вплоть до ее остановки при ранениях, несовместимых с жизнью игрока.

Другое направление — изменение способов задания объектов, используя базы данных и/или файлы.

Третье направление — изменение траекторий движения, как игрока, так и противников.

Четвертое направление — добавление нового вида (класса) противников, отличающихся от безобидных пока НЛО, после чего создайте для них общий класс, от которого они будут наследоваться (принцип наследования).

Не забывайте и про принцип полиморфизма, пусть методы родственных классов называются одинаково, а действуют по-разному.


NEW: Наш Чат, в котором вы можете обсудить любые вопросы, идеи, поделиться опытом или связаться с администраторами.


Помощь проекту:

  • Subject:
    C# Tutorials
  • Learning Time: 3 hours

In this tutorial we will create a simple platform game in visual studio using C# (sharp) programming language. This game will have points to collect, blocks to jump on to and a door to end the level. This is a basic level programming for a platform game and you should be trying to create another level once this is completed. There will be moving platforms that moves left to right and up and download in the game. We will get the player to travel with those platforms and make it into a nice and interactive little game using only windows forms and c# programming. Please note – this program was done as a prototype or proof of concept in windows form. This is why we didn’t use any pictures in it. All of the elements in the program are picture boxes so you can technically use your own images for the player, coins, door and platforms. So have fun with it and make it even better as your own game.

Lesson Objective –

  1. Create a platform game using picture boxes
  2. Allow the player to land on top of the picture boxes
  3. Run loops to search where the play has landed and take appropriate action
  4. Use foreach loop to search individual components in visual studio controls
  5. Assign TAG’s to platforms and interact with them
  6. Assign TAG’s to coins and interact with them
  7. Include a game completion format

Full Video Tutorial –

note- There will be some flickering when the character moves and jumps onto the platform, this is caused because of Visual Studio debugging not because of the code, the game will still be working as usual. 

Download Platform Game Project on GitHub

Full Source Code For this game –

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

// Created by MOOICT.COM
// For educational Purposes Only

namespace Platform_Game_Tutorial_MOO_ICT
{
    public partial class Form1 : Form
    {

        bool goLeft, goRight, jumping, isGameOver;

        int jumpSpeed;
        int force;
        int score = 0;
        int playerSpeed = 7;

        int horizontalSpeed = 5;
        int verticalSpeed = 3;

        int enemyOneSpeed = 5;
        int enemyTwoSpeed = 3;



        public Form1()
        {
            InitializeComponent();
        }

        private void MainGameTimerEvent(object sender, EventArgs e)
        {
            txtScore.Text = "Score: " + score;

            player.Top += jumpSpeed;

            if (goLeft == true)
            {
                player.Left -= playerSpeed;
            }
            if (goRight == true)
            {
                player.Left += playerSpeed;
            }

            if (jumping == true && force < 0)
            {
                jumping = false;
            }

            if (jumping == true)
            {
                jumpSpeed = -8;
                force -= 1;
            }
            else
            {
                jumpSpeed = 10;
            }

            foreach(Control x in this.Controls)
            {
                if (x is PictureBox)
                {


                    if ((string)x.Tag == "platform")
                    {
                        if (player.Bounds.IntersectsWith(x.Bounds))
                        {
                            force = 8;
                            player.Top = x.Top - player.Height;


                            if ((string)x.Name == "horizontalPlatform" && goLeft == false || (string)x.Name == "horizontalPlatform" && goRight == false)
                            {
                                player.Left -= horizontalSpeed;
                            }


                        }

                        x.BringToFront();

                    }

                    if ((string)x.Tag == "coin")
                    {
                        if (player.Bounds.IntersectsWith(x.Bounds) && x.Visible == true)
                        {
                            x.Visible = false;
                            score++;
                        }
                    }


                    if ((string)x.Tag == "enemy")
                    {
                        if (player.Bounds.IntersectsWith(x.Bounds))
                        {
                            gameTimer.Stop();
                            isGameOver = true;
                            txtScore.Text = "Score: " + score + Environment.NewLine + "You were killed in your journey!!";
                        }
                    }

                }
            }


            horizontalPlatform.Left -= horizontalSpeed;

            if (horizontalPlatform.Left < 0 || horizontalPlatform.Left + horizontalPlatform.Width > this.ClientSize.Width)
            {
                horizontalSpeed = -horizontalSpeed;
            }

            verticalPlatform.Top += verticalSpeed;

            if (verticalPlatform.Top < 195 || verticalPlatform.Top > 581)
            {
                verticalSpeed = -verticalSpeed;
            }


            enemyOne.Left -= enemyOneSpeed;

            if (enemyOne.Left < pictureBox5.Left || enemyOne.Left + enemyOne.Width > pictureBox5.Left + pictureBox5.Width)
            {
                enemyOneSpeed = -enemyOneSpeed;
            }

            enemyTwo.Left += enemyTwoSpeed;

            if (enemyTwo.Left < pictureBox2.Left || enemyTwo.Left + enemyTwo.Width > pictureBox2.Left + pictureBox2.Width)
            {
                enemyTwoSpeed = -enemyTwoSpeed;
            }


            if (player.Top + player.Height > this.ClientSize.Height + 50)
            {
                gameTimer.Stop();
                isGameOver = true;
                txtScore.Text = "Score: " + score + Environment.NewLine + "You fell to your death!";
            }

            if (player.Bounds.IntersectsWith(door.Bounds) && score == 26)
            {
                gameTimer.Stop();
                isGameOver = true;
                txtScore.Text = "Score: " + score + Environment.NewLine + "Your quest is complete!";
            }
            else
            {
                txtScore.Text = "Score: " + score + Environment.NewLine + "Collect all the coins";
            }


        }

        private void KeyIsDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Left)
            {
                goLeft = true;
            }
            if (e.KeyCode == Keys.Right)
            {
                goRight = true;
            }
            if (e.KeyCode == Keys.Space && jumping == false)
            {
                jumping = true;
            }
        }

        private void KeyIsUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Left)
            {
                goLeft = false;
            }
            if (e.KeyCode == Keys.Right)
            {
                goRight = false;
            }
            if (jumping == true)
            {
                jumping = false;
            }

            if (e.KeyCode == Keys.Enter && isGameOver == true)
            {
                RestartGame();
            }


        }

        private void RestartGame()
        {

            jumping = false;
            goLeft = false;
            goRight = false;
            isGameOver = false;
            score = 0;

            txtScore.Text = "Score: " + score;

            foreach (Control x in this.Controls)
            {
                if (x is PictureBox && x.Visible == false)
                {
                    x.Visible = true;
                }
            }


            // reset the position of player, platform and enemies

            player.Left = 72;
            player.Top = 656;

            enemyOne.Left = 471;
            enemyTwo.Left = 360;

            horizontalPlatform.Left = 275;
            verticalPlatform.Top = 581;

            gameTimer.Start();


        }
    }
}

На данном уроке мы разработаем простую мини игру «Угадай число» на языке C#. Суть игры простой: компьютер загадывает число от 0 до 100, выдаст подсказку — больше ли это число 50 или нет, затем сравнит введенное пользователем число с загаданным. Загадывание числа будет реализовано с помощью генератора случайных чисел:

Random rand = new Random();
int i = rand.Next(100);

Число «100» можно поменять. Если задать число «50», тогда компьютер будет загадывать от 0 до 50. Чтобы создать игру зайдите в Visual Studio, создайте проект «Консольное приложение (.NET Framework)» на языке C# и перепишите код:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ugaday_chislo
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.OutputEncoding = Encoding.GetEncoding(866);
            Console.InputEncoding = Encoding.GetEncoding(866);

            char again = 'y';
            Random rand = new Random();

            while (again == 'y')
            {
                int i = rand.Next(100);

                Console.WriteLine("Компьютер загадал число от 0 до 100");

                if (i < 50) Console.WriteLine("Число меньше 50");
                else Console.WriteLine("Число больше или равно 50");

                int x = Convert.ToInt32(Console.ReadLine());

                if (i == x) Console.WriteLine("Поздравляем! Вы победили свой компьютер!");
                else Console.WriteLine("Вы проиграли! Компьютер загадал число {0}", i);

                Console.WriteLine("Попробовать еще? (y = Да, n = Нет)");
                again = Convert.ToChar(Console.ReadLine());

            }
        }
    }
}

Результат программы:

Создание мини игры на C#. Угадай число.

Внимательно изучите код и попробуйте усовершенствовать его. Свои примеры пишите в комментариях, а я с удовольствием их посмотрю.




  • Виктор Черемных



  • 20 сентября, 2018



  • 6 Comments

6 ответов к “Создание мини игры на C#. Угадай число.”

В тексте ошибка. нужно в блоке » else Console.WriteLine(«Число больше или меньше 50″);» написать «Число больше или РАВНО» …

Когда в первый раз запустил, не сразу понял, как это больше или меньше.
Но в целом спасибо

Большое спасибо за сообщение!)) Исправил))

Спасибо за идею. Вот изучаю C#
Переделал Ваш вариант (не без помощи Яндекса). Теперь можно самому выбрать число до скольки отгадывать. А также программа считает количество попыток

Console.OutputEncoding = Encoding.GetEncoding(866);
Console.InputEncoding = Encoding.GetEncoding(866);
char again = ‘y’;
Random rand = new Random();
while (again == ‘y’)
{
Console.Clear();
Console.WriteLine(«Введите целое положительное число»);
int num = Convert.ToInt32(Console.ReadLine());
int i = rand.Next(num + 1);
int x = -1;
Console.WriteLine(«Компьютер загадал число от 0 до {0}», num);
if (i < (num / 2)) Console.WriteLine(«Число меньше {0}», num / 2);
else Console.WriteLine(«Число больше или равно {0}», num / 2);
int count = 1;
while (x!=i)
{
x = Convert.ToInt32(Console.ReadLine());
if (i == x)
{
Console.WriteLine(«Поздравляем! Вы победили свой компьютер! Вам потребовалось {0} попыток»,count);
break;
}
else if(i<x) Console.WriteLine(«Компьютер загадал меньше»);
else Console.WriteLine(«Компьютер загадал больше»);
count++;
}
Console.WriteLine(«Попробовать еще? (y = Да, n = Нет)»);
again = Convert.ToChar(Console.ReadLine());
}

Отлично)) Хорошая доработка)) Надеюсь и дальше будете изучать!)

А такой вариант?
static void Main(string[] args)
{
Random rnd = new Random();
int t = rnd.Next(0, 100);
// Console.WriteLine(t);
Console.WriteLine(«ПК загадал число від 0 до 100. Угадайте это число!»);
int w;
int sprob = 0;
start: Console.WriteLine(«Введите это число»);
w = Int32.Parse(Console.ReadLine());
if (w!=t)
{
if (w<t)
{
Console.WriteLine(«Ви НЕ угадали.Число должно быть больше!»);
}
else
{
Console.WriteLine(«Ви НЕ угадали.Число должно быть меньше!»);
}
Console.WriteLine(«Спробуйте ще раз»); sprob++; goto start;
}
else
{
Console.WriteLine(«Ви угадали. Молодец! Поздравляю»);
Console.WriteLine(«Количество проб:» + sprob);
}
Console.ReadKey();
}

Отлично! Такой вариант тоже хороший))

Добавить комментарий

Группа в VK

Обнаружили опечатку?

Сообщите нам об этом, выделите текст с ошибкой и нажмите Ctrl+Enter, будем очень признательны!

Свежие статьи

Облако меток

Похожие статьи

Entity Framework

Entity Framework

ADO.NET Entity Framework (EF) — объектно-ориентированная технология доступа к данным, является object-relational mapping (ORM) решением для .NET Framework от Microsoft. Предоставляет возможность взаимодействия с объектами

Работа с базой данных в C#

Работа с базой данных в C#

В данной статье мы подробно поговорим о разработке небольшого приложения с помощью Visual Studio базы данных и языка C#. Советуем поэтапно выполнять все инструкции из

Создание сканера портов

Создание сканера портов

В прошлой статье «Сокеты в C#» мы познакомились с сокетами и подробно рассмотрели классы для работы с ними. В этой статье мы разработаем простое приложение

Сокеты в С#

Сокеты в С#

Сокет — это один конец двухстороннего канала связи между двумя программами, работающими в сети. Используя два сокета, можно передавать данные между разными процессами (локальными или

Настройка окружения.

Прежде чем приступить к весёлой части с кодом, придётся пройти муторную, но важную часть с настройкой sfml. Данный гайд написан для Visual Studio 2019 на Windows. Установка для VS 2017 практически идентична, но могут быть незначительные отличия. Для других платформ крайне рекомендуется поискать гайд по настройке именно для вашего окружения. Ошибки на этом этапе, в лучшем случае, не дадут проекту скомпилироваться, в худшем – скомпилируются неправильно и вынесут вам мозг.

Переходим на главный сайт библиотеки и скачиваем последнюю стабильную версию (2.5.1 к моменту написания статьи). Выбираем для С++ 15(2017) 32-бита. Установка 64-битной версии идентична, для экономии времени сосредоточимся на более универсальной.

Распаковываем архив в удобную директорию, можно сразу сохранить в буфер путь до содержимого папки, в моем случае – это C:SFML-2.5.1.

Открываем VS-2019, создаем новое консольное приложение Windows, Называем проект FirstGameEngine, получаем консольный хеллоуворлд.

Теперь включаем концентрацию на максимум, задача довольно простая, но почти каждый допускает ошибку во время первой настройки. Открываем вкладку Проект, в самом низу выбираем свойства: FirstGameEngine.

Первый игровой движок на С++ и SFML

Выставляем конфигурацию Все конфигурации и платформу Win32. Выбираем пункт С/С++ → Общие, находим Дополнительные каталоги включаемых файлов – здесь нужно указать путь до папки include. Вставляем путь из буфера и дописываем, как сделал я. Если сомневаетесь, нажмите изменить и найдите папку через эксплорер.

Первый игровой движок на С++ и SFML

Спускаемся в Компоновщик → Дополнительные каталоги библиотек и проделываем тоже самое, но уже с папкой lib.

Первый игровой движок на С++ и SFML

Переключаем Конфигурацию на Debug. Открываем Компоновщик → Ввод → Дополнительные зависимости. Копируем этот перечень sfml-graphics-d.lib;sfml-window-d.lib;sfml-system-d.lib;sfml-audio-d.lib; и аккуратно, не стирая и не перезаписывая уже имеющиеся записи, вставляем его в начало списка.

Первый игровой движок на С++ и SFML

Переключаемся на Release и так же аккуратно вставляем sfml-graphics.lib;sfml-window.lib;sfml-system.lib;sfml-audio.lib;

Теперь поочередно запускаем Debug и Release, ловим по ошибке. Этот шаг необходим, чтобы студия создала папки проекта с exe-файлами. Сразу найдите эти каталоги. Их расположение зависит от настроек студии. Обычно они создаются на уровень выше папки с кодом. Теперь возвращаемся к распакованному архиву sfml, находим папку bin и копируем все бинарники с символом d в названии плюс openal32.bin в папку Debug, и то же самое без d + openal32.bin в Release.

Должна получиться такая картина:

Первый игровой движок на С++ и SFML

Самая нудная часть позади.

Написание первого игрового движка на С++.

К файлу FirstGameEngine.cpp мы вернемся чуть позже. Его единственная задача – это запустить в функции main() наш движок.

Класс персонажа.

Bob – простой класс для представления фигурки персонажа, управляемой игроком. Код класса будет легко расширяться, а что самое главное – его несложно переписать под любой другой игровой объект, который вы захотите добавить. Для этого потребуется заменить текстуру и описать поведение нового объекта в методе update().

Bob.h

Создаем новый заголовочный файл. Кликаем Проект Добавить новый элемент Файл заголовка. Называем Bob.h и объявляем следующие поля и методы:

        #pragma once
#include <SFML/Graphics.hpp>
 
using namespace sf;
 
class Bob
{
    // Все private переменные могут быть доступны только внутри объекта
private:
 
    // Позиция Боба
    Vector2f m_Position;
 
    // Объявляем объект Sprite
    Sprite m_Sprite;
 
    // Добавляем текстуру
    Texture m_Texture;
 
    // Логические переменные для отслеживания направления движения
    bool m_LeftPressed;
    bool m_RightPressed;
 
    // Скорость Боба в пикселях в секунду
    float m_Speed;
 
    // Открытые методы
public:
 
    // Настраиваем Боба в конструкторе
    Bob();
 
    // Для отправки спрайта в главную функцию
    Sprite getSprite();
 
    // Для движения Боба
    void moveLeft();
 
    void moveRight();
 
    // Прекращение движения
    void stopLeft();
 
    void stopRight();
 
    // Эта функция будет вызываться на каждый кадр
    void update(float elapsedTime);
 
};
    

Здесь мы объявили поля типа Texture и Sprite. Дальше мы свяжем их, и любое действие на экране с объектом Sprite будет сопровождаться изображением Боба:

Первый игровой движок на С++ и SFML

Сохраните это изображение в директорию FirstGameEngine/FirstGameEngine.

Bob.cpp

Приступим к реализации.

По той же схеме создаем файл Bob.cpp, только выбираем Файл С++. Теперь добавляем в файл код:

        #include "bob.h"
 
Bob::Bob()
{
    // Вписываем в переменную скорость Боба
    m_Speed = 400;
 
    // Связываем текстуру и спрайт
    m_Texture.loadFromFile("bob.png");
    m_Sprite.setTexture(m_Texture);     
 
    // Устанавливаем начальную позицию Боба в пикселях
    m_Position.x = 300;
    m_Position.y = 300;
 
}
 
// Делаем приватный спрайт доступным для функции draw()
Sprite Bob::getSprite()
{
    return m_Sprite;
}
 
void Bob::moveLeft()
{
    m_LeftPressed = true;
}
 
void Bob::moveRight()
{
    m_RightPressed = true;
}
 
void Bob::stopLeft()
{
    m_LeftPressed = false;
}
 
void Bob::stopRight()
{
    m_RightPressed = false;
}
 
// Двигаем Боба на основании пользовательского ввода в этом кадре,
// прошедшего времени и скорости
void Bob::update(float elapsedTime)
{
    if (m_RightPressed)
    {
        m_Position.x += m_Speed * elapsedTime;
    }
 
    if (m_LeftPressed)
    {
        m_Position.x -= m_Speed * elapsedTime;
    }
 
    // Теперь сдвигаем спрайт на новую позицию
    m_Sprite.setPosition(m_Position);   
 
}
    

В конструкторе мы установили значение переменной m_Speed на 400. Это значит, что Боб пересечет экран шириной в 1920 пикселей за 5 секунд. Также мы загрузили файл Bob.png в Texture и связали его с объектом Sprite. В переменных m_Position.x и m_Position.y установлено начальное положение Боба. Не забывайте, что в С++ координаты отсчитываются от верхнего левого угла и ось-у направлена вниз, не потеряйте Боба.

Функция update обрабатывает два If. Первое If проверяет, нажата ли правая кнопка (m_RightPressed), а второе следит за левой (m_LeftPressed). В каждом If скорость (m_Speed) умножается на elapsedTime. Переменная elapsedTime рассчитывается в функции Start движка (класс Engine). Им мы сейчас и займемся.

Engine.h

Создаем новый заголовочный файл Engine.h:

        #pragma once
#include <SFML/Graphics.hpp>
#include "Bob.h";
 
using namespace sf;
 
class Engine
{
private:
 
    RenderWindow m_Window;  
 
    // Объявляем спрайт и текстуру для фона
    Sprite m_BackgroundSprite;
    Texture m_BackgroundTexture;
 
    // Экземпляр Боба
    Bob m_Bob;
 
    void input();
    void update(float dtAsSeconds);
    void draw();
 
public:
    // Конструктор движка
    Engine();
 
    // Функция старт вызовет все приватные функции
    void start();
 
};
    

Класс библиотеки SFML, RenderWIndow, используется для рендера всего, что есть на экране. Переменные Sprite и Texture нужны для создания фона. Также в заголовке мы объявили экземпляр класса Bob.

Engine.cpp

Здесь мы реализуем конструктор и функцию start(). Создаем файл класса так же, как для Bob.cpp, и добавляем в него код:

        #include "Engine.h"
 
Engine::Engine()
{
    // Получаем разрешение экрана, создаем окно SFML и View
    Vector2f resolution;
    resolution.x = VideoMode::getDesktopMode().width;
    resolution.y = VideoMode::getDesktopMode().height;
 
    m_Window.create(VideoMode(resolution.x, resolution.y),
        "Simple Game Engine",
        Style::Fullscreen);
 
    // Загружаем фон в текстуру
    // Подготовьте изображение под ваш размер экрана в редакторе
    m_BackgroundTexture.loadFromFile("background.jpg");
 
    // Связываем спрайт и текстуру
    m_BackgroundSprite.setTexture(m_BackgroundTexture);
 
}
 
void Engine::start()
{
    // Расчет времени
    Clock clock;
 
    while (m_Window.isOpen())
    {
        // Перезапускаем таймер и записываем отмеренное время в dt
        Time dt = clock.restart();
 
        float dtAsSeconds = dt.asSeconds();
 
        input();
        update(dtAsSeconds);
        draw();
    }
}
    

Конструктор получает разрешение экрана и разворачивает игру на весь экран с помощью m_Window.create, загружается Texture и связывается с объектом Sprite.

В качестве фона вы можете использовать любое изображение, ниже я выложу своё. Рекомендую подобрать или масштабировать его по размерам вашего рабочего стола. Пункт не критичный, но смотрится приятнее, а в рамках данного курса мы не будем разбирать работу с окном и его размерами. Переименуйте файл в background.jpg и поместите в каталог FirstGameEngine/FirstGameEngine.

Можете воспользоваться моим примером:

Первый игровой движок на С++ и SFML

Игровой цикл.

Следующие три функции будут описаны каждая в отдельном файле, но при этом они должны быть частью Engine.h. Поэтому в начале каждого файла укажем директиву #include «Engine.h», так что Visual Studio будет знать, что мы делаем. Это делается для удобства дальнейшего масштабирования проекта.

Обрабатываем пользовательский ввод

        #include "Engine.h"
 
void Engine::input()
{
    // Обрабатываем нажатие Escape
    if (Keyboard::isKeyPressed(Keyboard::Escape))
    {
        m_Window.close();
    }
 
    // Обрабатываем нажатие клавиш движения
    if (Keyboard::isKeyPressed(Keyboard::A))
    {
        m_Bob.moveLeft();
    }
    else
    {
        m_Bob.stopLeft();
    }
 
    if (Keyboard::isKeyPressed(Keyboard::D))
    {
        m_Bob.moveRight();
    }
    else
    {
        m_Bob.stopRight();
    }                       
 
}
    

Функция input обрабатывает нажатия клавиш через константу Keyboard::isKeyPressed, предоставляемую SFML. При нажатии Escape m_Window будет закрыто. Для клавиш A и D вызывается соответствующая функция движения.

Обновляем игровые объекты

Теперь опишем функцию update. Её задача вызвать аналогичную функцию обновления состояния у всех игровых объектов. В нашем случае это только Bob.

Создаём файл Update.cpp и добавьте в него код:

        #include "Engine.h"
 
using namespace sf;
 
void Engine::update(float dtAsSeconds)
{
    m_Bob.update(dtAsSeconds);
}
    

Отрисовка экрана.

Это последняя функция класса Engine, её задача – отрисовать все объекты текущего экрана. Создайте файл Draw.cpp и добавьте в него код:

        #include "Engine.h"
 
void Engine::draw()
{
    // Стираем предыдущий кадр
    m_Window.clear(Color::White);
 
    // Отрисовываем фон
    m_Window.draw(m_BackgroundSprite);
    // И Боба
    m_Window.draw(m_Bob.getSprite());
 
    // Отображаем все, что нарисовали
    m_Window.display();
}
    

Экран каждый виток цикла очищается методом clear. Первым делом должен быть отрисован фон, чтобы потом поверх него можно было поместить Боба.

Запускаем движок!

Теперь вернемся к FirstGameEngine.cpp.

        #include "Engine.h"
 
int main()
{
    // Объявляем экземпляр класса Engine
    Engine engine;
 
    // Вызываем функцию start
    engine.start();
 
    // Останавливаем программу программу, когда движок остановлен
    return 0;
}
    

Наш игровой движок, как и положено первой работе, получился очень простым: он умеет только двигать главный объект и закрывать программу. Он не умеет обрабатывать столкновения, работать с интерфейсом и еще много чего. Возможно, этим мы займемся позже. Однако он отлично описывает то, как строится ядро игрового проекта с нуля. К тому же, в него довольно легко добавлять новые объекты и расширять функционал. Попробуйте, в качестве практики, добавить второго боба, управляемого клавишами J и L, у вас уже есть для этого все необходимые знания. Или поменяйте фон, если Боб выходит за границу экрана. Задачка уже посложней, но тоже вам по силам. =)

Понравилась статья? Поделить с друзьями:
  • Как написать игру марио
  • Как написать игру майнкрафт
  • Как написать игру крестики нолики на питоне
  • Как написать игру крестики нолики на python
  • Как написать игру кликер на python