Код марио, музыка и взаимодействие с врагами
Тут я сразу уже приведу код- после предыдущей главы всё уже должно быть понятным. При этом мы ещё из этого кода научимся как ввести в игру взаимодействие с врагами, а также музыку.
Все необходимые файлы ты можешь скачать тут: https://yadi.sk/d/dj0sHQi63Mm45U
КОД НИЖЕ
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp> // библиотека для работы со звуком
using namespace sf;
float offsetX=0, offsetY=0; // смещения карты
// сама карта
const int H = 17;
const int W = 150;
String TileMap[H] = {
"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"0 0",
"0 w 0",
"0 w w w 0",
"0 w kk 0",
"0 k k k k 0",
"0 c k kkk kkk w 0",
|
|
"0 r k k k 0",
"0 rr k k 0",
"0 rrr kk 0",
"0 c kckck rrrr 0",
"0 t0 rrrrr 0",
"0G 00 t0 rrrrrr G 0",
"0 d g d 00 00 rrrrrrr 0",
"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",
"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",
|
|
"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",
};
// класс игрока, всё как в предыдущей игре
class PLAYER {
public:
float dx,dy;
FloatRect rect;
bool onGround;
Sprite sprite;
float currentFrame;
// конструктор класса (начальные данные)
PLAYER(Texture &image) {
sprite.setTexture(image);
rect = FloatRect(100,180,16,16);
dx=dy=0.1;
currentFrame = 0;
}
// перемещение персонажа
void update(float time) {
rect.left += dx * time;
Collision(0);
if (!onGround) dy=dy+0.0005*time;
rect.top += dy*time;
onGround=false;
Collision(1);
currentFrame += time * 0.005;
if (currentFrame > 3) currentFrame -= 3;
if (dx>0) sprite.setTextureRect(IntRect(112+31*int(currentFrame),144,16,16));
if (dx<0) sprite.setTextureRect(IntRect(112+31*int(currentFrame)+16,144,-16,16));
sprite.setPosition(rect.left - offsetX, rect.top - offsetY);
dx=0;
}
|
|
// обработка столкновений
void Collision(int num) {
for (int i = rect.top/16 ; i<(rect.top+rect.height)/16; i++)
for (int j = rect.left/16; j<(rect.left+rect.width)/16; j++) {
if ((TileMap[i][j]=='P') || (TileMap[i][j]=='k') || (TileMap[i][j]=='0') || (TileMap[i][j]=='r') || (TileMap[i][j]=='t')) {
if (dy>0 && num==1) { rect.top = i*16 - rect.height; dy=0; onGround=true; }
if (dy<0 && num==1) { rect.top = i*16 + 16; dy=0;}
if (dx>0 && num==0) { rect.left = j*16 - rect.width; } if (dx<0 && num==0) { rect.left = j*16 +16;}
}
if (TileMap[i][j]=='c') { // TileMap[i][j]=' '; }
}
}
};
// класс для учёта врага (он похож на класс игрока)
class ENEMY {
public:
float dx,dy;
FloatRect rect;
Sprite sprite;
float currentFrame;
bool life; // жив или мёртв
// конструктор (начальные значения)
void set(Texture &image, int x, int y) {
sprite.setTexture(image);
|
|
rect = FloatRect(x,y,16,16);
dx=0.05;
currentFrame = 0;
life=true;
}
// простейший интеллект врага- будет двигаться только по иксу, а при столкновении двигаться в обратную сторону
void update(float time) {
rect.left += dx * time;
Collision();
currentFrame += time * 0.005;
if (currentFrame > 2) currentFrame -= 2;
sprite.setTextureRect(IntRect(18*int(currentFrame), 0, 16,16));
if (!life) sprite.setTextureRect(IntRect(58, 0, 16,16));
sprite.setPosition(rect.left - offsetX, rect.top - offsetY);
}
void Collision() {
for (int i = rect.top/16 ; i<(rect.top+rect.height)/16; i++)
for (int j = rect.left/16; j<(rect.left+rect.width)/16; j++)
if ((TileMap[i][j]=='P') || (TileMap[i][j]=='0')) {
if (dx>0) { rect.left = j*16 - rect.width; dx*=-1; } else if (dx<0) { rect.left = j*16 + 16; dx*=-1; }
}
}
};
int main() {
RenderWindow window(VideoMode(400, 250), "Mario");
Texture tileSet; tileSet.loadFromFile("Mario_Tileset.png");
PLAYER Mario(tileSet);
ENEMY enemy;
enemy.set(tileSet,48*16,13*16);
Sprite tile(tileSet);
SoundBuffer buffer; // переменная для работы со звуком
buffer.loadFromFile("Jump.ogg"); // загрузка звука (будет запускаться при прыжке)
Sound sound(buffer); // помещение в буфер- будем проигрывать только при прыжке (это далее прописывается при нажатии клавиши вверх)
Music music; // фоновая музыка
music.openFromFile("Mario_Theme.ogg"); // загрузка из файла
music.play(); // проигрывание музыки
Clock clock;
// главный цикл игры
while (window.isOpen()) {
float time = clock.getElapsedTime().asMicroseconds();
clock.restart();
time = time/500; // здесь регулируем скорость игры
if (time > 20) time = 20;
Event event;
while (window.pollEvent(event)) {
if (event.type == Event::Closed) window.close();
}
// что происходит при нажатии клавиш
if (Keyboard::isKeyPressed(Keyboard::Left)) Mario.dx=-0.1;
if (Keyboard::isKeyPressed(Keyboard::Right)) Mario.dx=0.1;
if (Keyboard::isKeyPressed(Keyboard::Up)) if (Mario.onGround) { Mario.dy=-0.27; Mario.onGround=false; sound.play();}
Mario.update(time);
enemy.update(time);
// пересечение прямоугольников игрока и врага- при пересечении закрасимся красным, а убивание- если мы на врага падаем
if (Mario.rect.intersects( enemy.rect ) ) {
if (enemy.life) {
if (Mario.dy>0) { enemy.dx=0; Mario.dy=-0.2; enemy.life=false;}
else Mario.sprite.setColor(Color::Red);
}
}
// задаём какое должно быть смещение карты
if (Mario.rect.left>200) offsetX = Mario.rect.left-200;
// отрисовка карты
window.clear(Color(107,140,255));
for (int i=0; i<H; i++)
for (int j=0; j<W; j++) {
if (TileMap[i][j]=='P') tile.setTextureRect( IntRect(143-16*3,112,16,16) );
if (TileMap[i][j]=='k') tile.setTextureRect( IntRect(143,112,16,16) );
if (TileMap[i][j]=='c') tile.setTextureRect( IntRect(143-16,112,16,16) );
if (TileMap[i][j]=='t') tile.setTextureRect( IntRect(0,47,32,95-47) );
if (TileMap[i][j]=='g') tile.setTextureRect( IntRect(0,16*9-5,3*16,16*2+5) );
if (TileMap[i][j]=='G') tile.setTextureRect( IntRect(145,222,222-145,255-222) );
if (TileMap[i][j]=='d') tile.setTextureRect( IntRect(0,106,74,127-106) );
if (TileMap[i][j]=='w') tile.setTextureRect( IntRect(99,224,140-99,255-224) );
if (TileMap[i][j]=='r') tile.setTextureRect( IntRect(143-32,112,16,16) );
if ((TileMap[i][j]==' ') || (TileMap[i][j]=='0')) continue;
tile.setPosition(j*16-offsetX,i*16 - offsetY) ;
window.draw(tile);
}
// накладывание персонажа и врага на уже нарисованную карту
window.draw(Mario.sprite);
window.draw(enemy.sprite);
// вывод всего на экран
window.display();
}
// завершение программы
return 0;
}
Коротко об OpenGL
OpenGL- это Open Graphic Library или открытая графическая библиотека. В отличие от SFML, это более низкоуровневая и универсальная библиотека графики. Но при этом она более сложная в освоении, на ней нужно писать больше кода. Также она работает с 3d объектами, а SFML поддерживает только 2d, т.е. плоские вещи. Многие современные игры используют OpenGL. Поэтому мы обязательно хотя бы кратко рассмотрим эту вещь ниже.
Для того чтобы в devcpp использовать OpenGL, не нужно каких-то специальных ухищрений. Заходим создать проект, выбираем вкладку Multimedia и там выбираем тип проекта OpenGL. Всё. Создастся файл со следующим содержанием (это тестовый код)
/**************************
* Includes
*
**************************/
#include <windows.h>
#include <gl/gl.h>
/**************************
* Function Declarations
*
**************************/
LRESULT CALLBACK WndProc (HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam);
void EnableOpenGL (HWND hWnd, HDC *hDC, HGLRC *hRC);
void DisableOpenGL (HWND hWnd, HDC hDC, HGLRC hRC);
/**************************
* WinMain
*
**************************/
int WINAPI WinMain (HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int iCmdShow)
{
WNDCLASS wc;
HWND hWnd;
HDC hDC;
HGLRC hRC;
MSG msg;
BOOL bQuit = FALSE;
float theta = 0.0f;
/* register window class */
wc.style = CS_OWNDC;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = "GLSample";
RegisterClass (&wc);
/* create main window */
hWnd = CreateWindow (
"GLSample", "OpenGL Sample",
WS_CAPTION | WS_POPUPWINDOW | WS_VISIBLE,
0, 0, 256, 256,
NULL, NULL, hInstance, NULL);
/* enable OpenGL for the window */
EnableOpenGL (hWnd, &hDC, &hRC);
/* program main loop */
while (!bQuit)
{
/* check for messages */
if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
{
/* handle or dispatch messages */
if (msg.message == WM_QUIT)
{
bQuit = TRUE;
}
else
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
}
else
{
/* OpenGL animation code goes here */
glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
glClear (GL_COLOR_BUFFER_BIT);
glPushMatrix ();
glRotatef (theta, 0.0f, 0.0f, 1.0f);
glBegin (GL_TRIANGLES);
glColor3f (1.0f, 0.0f, 0.0f); glVertex2f (0.0f, 1.0f);
glColor3f (0.0f, 1.0f, 0.0f); glVertex2f (0.87f, -0.5f);
glColor3f (0.0f, 0.0f, 1.0f); glVertex2f (-0.87f, -0.5f);
glEnd ();
glPopMatrix ();
SwapBuffers (hDC);
theta += 1.0f;
Sleep (1);
}
}
/* shutdown OpenGL */
DisableOpenGL (hWnd, hDC, hRC);
/* destroy the window explicitly */
DestroyWindow (hWnd);
return msg.wParam;
}
/********************
* Window Procedure
*
********************/
LRESULT CALLBACK WndProc (HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
return 0;
case WM_CLOSE:
PostQuitMessage (0);
return 0;
case WM_DESTROY:
return 0;
case WM_KEYDOWN:
switch (wParam)
{
case VK_ESCAPE:
PostQuitMessage(0);
return 0;
}
return 0;
default:
return DefWindowProc (hWnd, message, wParam, lParam);
}
}
/*******************
* Enable OpenGL
*
*******************/
void EnableOpenGL (HWND hWnd, HDC *hDC, HGLRC *hRC)
{
PIXELFORMATDESCRIPTOR pfd;
int iFormat;
/* get the device context (DC) */
*hDC = GetDC (hWnd);
/* set the pixel format for the DC */
ZeroMemory (&pfd, sizeof (pfd));
pfd.nSize = sizeof (pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW |
PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 16;
pfd.iLayerType = PFD_MAIN_PLANE;
iFormat = ChoosePixelFormat (*hDC, &pfd);
SetPixelFormat (*hDC, iFormat, &pfd);
/* create and enable the render context (RC) */
*hRC = wglCreateContext( *hDC );
wglMakeCurrent( *hDC, *hRC );
}
/******************
* Disable OpenGL
*
******************/
void DisableOpenGL (HWND hWnd, HDC hDC, HGLRC hRC)
{
wglMakeCurrent (NULL, NULL);
wglDeleteContext (hRC);
ReleaseDC (hWnd, hDC);
}
Скомпилировав этот код, получим треугольник с цветными краями, который вращается.
...
Научимся теперь делать рисовать простые плоские статичные фигуры. Для этого нам нужно найти код:
/* OpenGL animation code goes here */
glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
glClear (GL_COLOR_BUFFER_BIT);
glPushMatrix ();
glRotatef (theta, 0.0f, 0.0f, 1.0f);
glBegin (GL_TRIANGLES);
glColor3f (1.0f, 0.0f, 0.0f); glVertex2f (0.0f, 1.0f);
glColor3f (0.0f, 1.0f, 0.0f); glVertex2f (0.87f, -0.5f);
glColor3f (0.0f, 0.0f, 1.0f); glVertex2f (-0.87f, -0.5f);
glEnd ();
glPopMatrix ();
SwapBuffers (hDC);
theta += 1.0f;
Sleep (1);
В нём мы убираем theta и sleep (задержку) в конце, далее убираем glRotatef- т.е. вращаться ничего не будет. В начале объявление theta тоже можно убрать (float theta = 0.0f; вот эту строку)
Остаётся вот такой сырой код:
glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
glClear (GL_COLOR_BUFFER_BIT);
glPushMatrix ();
glRotatef (theta, 0.0f, 0.0f, 1.0f);
glBegin (GL_TRIANGLES);
// здесь будет рисование
glEnd ();
glPopMatrix ();
SwapBuffers (hDC);
Первая строчка glClearColor отвечает за заливаемый фон. Цвета тут устроены по системе RGB- Red Green Blue или красный зелёный голубой. Нули дают нам чёрный цвет (отсутствие), а единицы- белый (смешение всех цветов). Используя эти 3 параметра в разных комбинациях, мы получаем разные цвета. Чтобы найти нужный цвет, нужно узнать его код в RGB (интернет и всякие пипетки в помощь)- например в 24-битной это выглядит так (по 8 бит или 256 кодов на каждый компонент) - 97, 126, 28. Теперь нам нужно это в долях выразить и записать: 97/255, 126/255, 28/255. Если код указан в 16-ричной системе счисления типа 9FA235, то нужно разбить по 2 цифры: 9F A2 35 и далее перевести в десятичную систему: 9*16+15, 10*16+2, 3*16+5 и опять выразить это в долях, можно даже самому не считать, а прям так выражениями и записывать. Т.е. аргументы будут такие: (9*16+15)/255, (10*16+2)/255, (3*16+5)/255. Можно даже изощриться и написать функции, которые тебе будут переводить из одного формата в другой, их для удобства можно писать даже в отдельном заголовочном файле.
Вторая строчка чистит экран, её мы не трогаем.
Далее- всё рисуемое заключается между glPushMatrix и glPopMatrix, это мы тоже не трогаем.
glBegin (GL_TRIANGLES); // здесь мы указываем- что именно будем рисовать. У нас указано по умолчанию GL_TRIANGLES, это значит что будет треугольник- он рисуется по 3 точкам.
Сначала научимся ставить точку. Чтобы ставить чисто точки, надо поменять GL_TRIANGLES на GL_POINTS. И далее до glEnd мы эти точки сколько нам надо ставим.
Для постановки точки мы указываем 2 вещи- цвет точки и её позицию. Сначала цвет, потом позиция.
glColor3f (0,1,0); glVertex2f (0,0);
Здесь у нас будет зелёная точка в позиции 0,0. Это значит центр координат, он у нас находится в центре графического окошка. Единица- это края окна. Как в декартовой системе. Например, -1,1 это будет влево по горизонтали до конца (-1) и вверх по вертикали до конца (1), т.е. левый верхний угол. Если мы поставим 0.5, то это будет посередине от центра до края. Т.е. положение точки тоже выражается в долях, как мы это делаем с цветами.
Чтобы поставить линию, нам нужно в glBegin указать GL_LINES. И отрезок ставится по 2 точкам. Например, если нам нужен чёрный отрезок с левого нижнего угла (но не впритык, а близко к нему) до правого верхнего, можно сделать так:
glColor3f (0,0,0); glVertex2f (-0.9,-0.8);
glColor3f (0,0,0); glVertex2f (0.9,0.8);
Можно поставить ещё одну линию, написав дальше код ещё 2 следующих точек, по которым построится вторая линия.
Если мы поставим цвета 2 точек, по которым строится линия, разными, то цвет будет в виде градиента- переливаться с одного до другого.
Аналогично мы можем треугольник сделать по 3 точкам.
Размер окна можно поменять вот в этой строчке: WS_CAPTION | WS_POPUPWINDOW | WS_VISIBLE,
0, 0, 256, 256,
Только вместо последних 256 поставить свои размеры. Причём один и тот же код работает для разных размеров, т.к. позиции указываются в долях- т.е. просто будет меняться масштаб фигуры в соответствии с размерами окна.
Для построения непрерывных графиков используем:
glBegin (GL_LINE_LOOP);
Тут конечная точка предыдущей линии будет начальной линией следующей.
Например, вот так мы можем нарисовать окружность на весь экран:
for(double a=0; a < 2*M_PI; a+=0.01) glVertex2f (cos(a),sin(a));
Главное не забыть подключить cmath для синуса и косинуса. Окружность рисуется по принципам полярных координат. M_PI это чисто пи, константа, она прописана в том же cmath.
Чтобы сплющить окружность в эллипс по горизонтали, мы домножаем синус на небольшой коэффициент, например 1.3. Если мы будем прибавлять или отнимать что-то с синусом, то круг будет двигаться вверх или вниз. Если же мы уже аргумент будем менять, то тут интереснее: если прибавить единицу к аргументу, то круг как бы наклонится на 45 градусов. Откуда именно так, полагаю что это из-за того что тангенс 45 градусов равен единице. Ты можешь со всем этим поэкспериментировать.
Ты можешь открыть справочник по высшей математике и посмотреть параметрически заданные графики- и далее реализовать их в OpenGL по полярной системе координат.
Вот этот код нарисует красивый листик конопли:
for(double a=0; a < 2*M_PI; a+=0.01) {
double r= 0.3*(1+sin(a))*(1+0.9*cos(8*a))*(1+0.1*cos(24*a));
glVertex2f (r*cos(a),r*sin(a)-0.5);
}
________________________________________________
РАЗДЕЛ 5
Практические Полезности
Программа с выбором действий
Часто встречается такой тип программы, в котором нам надо выбрать одно из действий. Иногда таких выборов в большой программе бывает несколько. Рассмотрим на примере вывода с комиссией с электронных кошельков.
Программа даёт нам 3 варианта, откуда вывести: с киви, с яндекс денег или ввести свою комиссию. Для киви и яндекса комиссия фиксирована.
Для подобных выборов уже разработано стандартное решение, я это делаю через специальную функцию:
int Select() {
cout << "Калькулятор вывода с комиссией" << endl;
_(); // это cout<<endl;
cout << "(0) Назначить свои комиссии" << endl;
cout << "(1) Яндекс деньги" << endl;
cout << "(2) Киви кошелёк" << endl;
int x; cin>>x; _(); return x;
}
Если у нас всего 2 варианта на выбор, можно использовать тип данных bool и вводить 0 или 1. В случае bool возвращать можно и противоположное. Вот пример с булевым значением функции:
bool NewGame() {
__(0); // это зачистка экрана system("CLS");
cout << "(0) Новый учёт\n(1) Продолжаем\n";
bool res; cin>>res; __(0); return !res;
}
Теперь вернёмся к калькулятору выбора с комиссией. Как используется эта функция выбора:
int k= Select();
if(k==0) {
// делаем что-то там своё
}
if(k==1) { опять что-то делаем уже другое }
И т.д. и т.п.
...
Вот пример всей программы для закрепления:
#include <iostream>
using namespace std;
void _() { cout << endl; }
void __(int k) {
if(k==0) system("CLS");
if(k==1) { _(); system("pause"); }
if(k==2) { __(1); __(0); }
}
int Select() {
cout << "Калькулятор вывода с комиссией" << endl;
_();
cout << "(0) Назначить свои комиссии" << endl;
cout << "(1) Яндекс деньги" << endl;
cout << "(2) Киви кошелёк" << endl;
int x; cin>>x; _(); return x;
}
int main() {
setlocale(0,"");
int k; double proc, stat; double $, _$;
while(1) {
k= Select();
if(k==0) {
cout << "Введите процент комиссии при выводе: "; cin>>proc; proc/=100;
cout << "Беспроцентная комиссия в денежных у.е: "; cin>>stat;
}
if(k==1) { proc= 0.03; stat= 45; }
if(k==2) { proc= 0.02; stat= 50; }
_();
bool povtor= true;
do {
cout << "Сколько денег на счету: "; cin>>$;
_$= ($-stat)/(1+proc);
if((k==1)&&(_$<500)) cout << "Минимальная сумма вывода с яндекса равна 500" << endl;
else {
cout << "Можно вывести: " << _$ << endl;
_();
cout << "(0) Выход\n(1) Ещё раз" << endl; cin>>povtor;
}
} while (povtor);
__(2);
}
}
Программа с учётом величин
Следующий тип программ это когда у нас учитываются какие-то величины. Это могут быть виртуальные валюты и очки опыта в игре или доходы и расходы в бюджетной программе. И эти величины у нас выводятся постоянно наверх программы. Посмотрим на простейшем примере учёта каких-то виртуальных баллов:
#include <iostream>
#include <string>
using namespace std;
// функция вывода величин наверх- сначала делается зачистка экрана, затем вывод
void info (string name, double money) {
system("CLS");
cout << name << " ($ " << money << ")";
cout << endl << endl; // разделение рабочей части программы от выводных полей
}
int main() {
setlocale(0,"");
string name; double money, saldo; // переменные для хранения данных лучше объявлять вне основного цикла программы чтобы они сотни раз не переобъявлялись с расходом памяти
// вводим начальные данные
cout << "Ваше имя: "; cin >> name;
cout << "Ваши деньги: "; cin >> money;
// учитываем эти данные в бесконечном цикле
while(true) {
info(name,money); // вывод того что у нас уже есть
// изменение учитываемой величины
cout << "! Вводить расход с минусом" << endl;
cout << "Приход/расход: "; cin >> saldo;
money+=saldo;
}
}
Программа с обработкой строк
Ещё один тип программ- мы вводим строку, а программе нужно из неё вычленить какие-то нужные данные, как-то их обработать и вывести нам результат. Такое случается чем дальше, тем чаще- это сильно расширяет возможности программирования. Ниже будет рассмотрен пример с учётом времени.
Я ввожу например 7:12 - 7:24 делал зарядку +
И программа должна понять, сколько минут я делал зарядку. Данные вводятся как строка. А потом она с этими минутами может что-то делать, например посчитать процент от всех деятельностей вообще.
Для хранения времени у нас будет специальный класс:
class vakit {
public:
int hours; int minutes;
};
А так мы будем переводить строковые данные во временные:
vakit ToVakit (string x) {
string Hours= "", Minutes= ""; // сначала строки пустые
int i= 0; // итератор для пробега по строке
while (x[i]!=':') Hours+=x[i++]; // пока не наткнулись на двоеточие, добавлять эту часть строки в часы
i++; // пропустить двоеточие
while (x[i]!='\0') Minutes+=x[i++]; // пока не достигли конца строки, добавлять оставшееся в минуты
vakit t; // создаём наш экземпляр временного типа данных
t.hours= StringToInt(Hours); // перевод из строки в число
t.minutes= StringToInt(Minutes);
return t;
}
А вот уже класс для хранения всей строки, которую мы и вводим:
class geler {
public:
// хранится начальное время, конечное, само название процесса и его знак- насколько процесс желательный
vakit start, finish; string process; int sign;
// вычисление этих самых минут
int TimeDist () {
return finish.minutes - start.minutes + (finish.hours - start.hours)*60 + 1 ;
}
};
И теперь функция перевода из строки в экземпляр класса geler. Делается всё аналогично как перевод в формат времени, только более сложно, т.к. нужно больше разных типов символов обработать:
geler ToGeler (string s) {
geler g;
string Time1= "", Time2= "", Process= "";
int i= 0;
while (s[i]!=' ') Time1+=s[i++];
i+=3;
while (s[i]!=' ') Time2+=s[i++];
i++;
while ((int)s[i+1]!=0) Process+=s[i++];
if(s[i]=='!') g.sign= 3;
if(s[i]=='+') g.sign= 2;
if(s[i]=='*') g.sign= 1;
if(s[i]=='-') g.sign= 0;
g.process= Process;
g.start= ToVakit(Time1);
g.finish= ToVakit(Time2);
return g;
}
Дата добавления: 2018-09-22; просмотров: 472; Мы поможем в написании вашей работы! |
Мы поможем в написании ваших работ!