Есть желание написать программу, реализующую действия ракеты и её цели. Задаются координаты цели для ракеты, стрелками на клавиатуре можно менять положение цели в 2-х мерном пространстве, ракета должна отслеживать цель. Все это должно производиться "параллельно"..
Код исходный большой(т.е там файлов листинга просто много). Я знаю, что один вольво отвечает на мои безумные посты, на него и надежда вся.
В общем, в коде я оставил комментарии, где происходит "неконтролируемое", они в 2х файлах main и realiz.cpp. Код в архиве...
Прикрепленные файлы
ev.zip ( 3.04 килобайт )
Кол-во скачиваний: 200
с одной проблемой в case разобрался. совсем забыл про brake...А вот почему поток изменения координаты мешени не вызывается - не пойму..:/
А можно объяснить, что ты задумывал сделать вот тут:
switch (choise), желательно - построчно... Особенное внимание, если можно, обратить на ПОСТОЯННОЕ создание потока MoveToTarget. Сколько их у тебя создается? Что делает каждый из них?
{
case 'n':
std::cout << "Exiting..";
exit(20);
case 'y':
Target target(sx, sy);
p.tarp = ⌖
rocket.LockTarget(target.GetXCoord(), target.GetYCoord());
myEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
SetEvent(myEvent);
MyEvent2 = CreateEvent(NULL, FALSE, FALSE, NULL);
SetEvent(MyEvent2);
while (target.TStatus)
{
if (kbhit() != 0)
{
key = getch();
TH2=CreateThread(NULL,0,
(LPTHREAD_START_ROUTINE) ChangeCoordTarget, &target, 0, &ID); }
TH=CreateThread(NULL,0, (LPTHREAD_START_ROUTINE) MoveToTarget, &p, 0, &ID);
}
}
switch (choise)
{
case 'n':// если ответ - n - выходим из программы.
std::cout << "Exiting..";
exit(20);
case 'y':
Target target(sx, sy);// создается объект класса Target
p.tarp = ⌖//полю tarp ,структуры содержащей указатели на классы Rocket и Target, //присваевается адрес объекта target
rocket.LockTarget(target.GetXCoord(), target.GetYCoord());//позиционируем координаты цели
myEvent = CreateEvent(NULL, FALSE, FALSE, NULL);//инициализация события для функции изменения //координаты цели
SetEvent(myEvent);//сброс , что бы не тормозить потоки.
MyEvent2 = CreateEvent(NULL, FALSE, FALSE, NULL);//для изменения координаты ракеты
SetEvent(MyEvent2);
while (target.TStatus)//цикл пока жива цель
{
if (kbhit() != 0)//если была нажата клавища
{
key = getch();//считать её в переменную key
TH2=CreateThread(NULL,0,
(LPTHREAD_START_ROUTINE) ChangeCoordTarget, &target, 0, &ID);//поток обрабатывает нажатие клавиши и перемешает цель
}
TH=CreateThread(NULL,0, (LPTHREAD_START_ROUTINE) MoveToTarget, &p, 0, &ID);//ракета постоянно контролирует положение цели и стремиться к ней.
}
}
Одну проблему нашел, где вычисляется соотношение координаты ракеты и координаты цели. сейчас пытаюсь исправить. Голова плохо варит, спал 4 часа..на рыбалку ездил)
Задумка неплохая, НО... Объясни мне, зачем у тебя потоки создаются, делают одно действие, и удаляются?
Я бы сделал так: Запускаешь сразу после того как ввел координаты цели, оба потока. Функции обоих потоков зацикливаешь, чтобы они не завершались, до тех пор, пока... Ну, например, пока цель не будет сбита (в этот момент какой-нибудь глобальный флажок перебросится в TRUE, и оба потока завершатся). А потом в основном потоке приложения уже читаешь клавишу, записываешь ее коды (да, да... Именно коды, все кнопки управления курсором возвращают 2 байта, первый = 0, второй - то, что ты обрабатываешь), на время изменения переменной, хранящей код нажатой клавиши, устанавливаешь событие, блокируя потоку ChangeCoordTarget доступ к этой переменной, пускай в это время он ждет снятия события (второй поток в это время может продолжать работать, его ничего не должно держать), а потом, как только переменная key "разблокирована", поток ChangeCoordTarget опять продолжает работать: читает содержимое key, и, если оно не = 0, изменяет позицию цели... Поскольку и один и второй поток у тебя работает с данными через указатели, то следующий же цикл чтения потоком MoveToTarget уже будет работать с обновленными координатами цели.
Единственное что, тебе понадобится сделать еще временную блокировку потока MoveToTarget на то время, пока изменяются координаты цели...
Понимаешь идею, или не совсем? У тебя что-то похожее, но не надо постоянно создавать/уничтожать потоки, и не надо блокировать работу одного потока на ВЕСЬ цикл работы другого, достаточно запретить им обращаться к одной и той же переменной в разных режимах (когда один - пишет, другой - читает)
Честно говоря не совсем. НЕ совсем я понимаю в синхронизации/блокировке потоков. Просто очень мало с этим работаю. Допустим у меня будет одна булевая переменная , назовем её ISALIVE; Цикл идет while(ISALIVE). это ясно.
Потом, как мне БЛОКИРОВАТЬ поток?с пом-щью wait-функций?
Не понял про коды проверять надо по hex-кодам?
Смотри... Я ничего не менял в файлах Rocket.cpp и Target.cpp... Вот все изменения, которые я сделал:
1) файл func.h добавлены описания:
extern char key;, все эти переменные определены в main.cpp
extern bool IsAlive;
extern HANDLE changeKeyEvent;
extern HANDLE startEvent;
#include "func.h"
bool ChangeCoordTarget(Target &tr)
{
WaitForSingleObject(startEvent, INFINITE);
SetEvent(startEvent);
while(IsAlive) {
WaitForSingleObject(changeKeyEvent, INFINITE);
if(key != 0) {
// ResetEvent(changeCoordEvent);
cout << (int)key << endl;
switch (key) {
case 72: // up
tr.y++;
std::cout << "\nY now : " << tr.y << '\n';
break;
case 80: //down
tr.y--;
std::cout << "\nY now : " << tr.y << '\n';
break;
case 75: //left
tr.x--;
std::cout << "\nX now : " << tr.x << '\n';
break;
case 77: // right
tr.x++;
std::cout << "\nX now : " << tr.x << '\n';
break;
}
// SetEvent(changeCoordEvent);
key = 0;
}
Sleep(10);
}
return true;
}
bool MoveToTarget(pointers& p)
{
WaitForSingleObject(startEvent, INFINITE);
SetEvent(startEvent);
while(IsAlive) {
p.rocp->GetRealTimeTCoord(p.tarp);
if (p.rocp->x != p.tarp->x)
if (p.tarp->x < 0) p.rocp->x--;
else p.rocp->x++;
if (p.rocp->y != p.tarp->y)
if (p.tarp->y < 0) p.rocp->y--;
else p.rocp->y++;
cout << "Missile: " << p.rocp->x << " ," << p.rocp->y << endl;
Sleep (1000); // <--- Изменить, а то не совсем честно получается - ракета медленно летит
p.rocp->Hit(p.tarp->TStatus);
if(!p.tarp->TStatus) {
IsAlive = false;
}
}
return true;
}
rocket.LockTarget(target.GetXCoord(), target.GetYCoord());Если нужны комментарии - скажи, я суть позже добавлю.
startEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
changeKeyEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
TH2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ChangeCoordTarget,
&target, 0, &ID); // поток обработки изменения координаты цели
TH = CreateThread(NULL,0, (LPTHREAD_START_ROUTINE) MoveToTarget,
&p, 0, &ID); // ракета постоянно контролирует положение цели и стремится к ней.
SetEvent(startEvent);
int ch;
while(kbhit()) getch();
while(IsAlive) {
if(kbhit()) {
if((ch = getch()) == 224) { // Откуда взялось 224 - не понял, всегда был 0
ResetEvent(changeKeyEvent);
key = getch();
SetEvent(changeKeyEvent);
}
else {
if(ch == 27) {
IsAlive = false;
}
}
}
Sleep(50);
}
} // switch(choise)
ну интересуют все закомментированные инструкции, в частности:
// switch(choise) - просто забыл убрать?
//Set и Reset Event - делал для теста,так я понимаю?
WaitForSingleObject(startEvent, INFINITE);и в начале потока ChangeCoordTarget, и в начале потока MoveToTarget(). Почему? Зачем? Что будет, если не делать SetEvent?
SetEvent(startEvent);
я сделал такое лицо сейчас -
У меня лишь предположение, что потоки не начнут свою работу?..
Добавлено через 3 мин.
Черт. я перестал вообще понимать что происходит. Тупо, често, вот сейчас тупо вставил твой код, попробывал "поиграться" и...приложение завершается , так сказать, не успев начаться. Я так понимаю надо добавить ивенты для смены координат...?или я ничего не понимаю..
bool IsAlive = true;Иначе оно инициализируется false, и "Усе пропало, шеф!!!" (С) "Бриллиантовая рука"
Volvo, скажу одно - тебе можно только позавидовать, у тебя столько практики в логике и кодинге..а ладно.щас подумаю получше.
Добавлено через 18 мин.
Ну, видимо, если убрать SetEvent ,допустим, в ChangeCoordTarget, то поток с "полетом ракеты" не узнает о том, что координата поменялась ...
Кстате, почему-то, если добавить строчку в
...
case 77: // right
tr.x++;
break;
}
// SetEvent(changeCoordEvent);
key = 0;
std::cout << "Target now on " << tr.x << " : " << tr.y;//!!!тут
}
if (p.rocp->x != p.rocp->TX)//если координата ракеты != коориданты цели
if (p.rocp->x < p.rocp->TX)//если координата Х ракеты меньше коориданты Х цели
if (p.rocp->TX < 0)//проверить, отрицательная или положительная координата х у ракеты
p.rocp->x++;//тогда сместить к цели
else
p.rocp->x++;//иначе , если кооридината ракеты выше положительная, то так же сместиться к ней
else if (p.rocp->x > p.rocp->TX)//если ракета находиться выше цели то..
if (p.rocp->TX < 0)//опять проверяем и т.д.тоже самое и координатой Y
p.rocp->x--;
else
p.rocp->x--;
if (p.rocp->y != p.rocp->TY)
if (p.rocp->y < p.rocp->TY)
if (p.rocp->TY < 0)
p.rocp->y++;
else
p.rocp->y++;
else if (p.rocp->y > p.rocp->TY)
if (p.rocp->TY < 0)
p.rocp->y--;
else
p.rocp->y--;
// ResetEvent(changeCoordEvent);
cout << (int)key << endl; // <--- Вот эту строчку
про аски-код - не заметил, извиняюсь.
Странно, но у меня почему-то происходит изменение координат ракеты так, как я описал, а не "правильно.
полный непонимат.
Будто ракета не получает кооридинаты цели.
может я что-не так написал?,,Да нет, ничего такого вроде бы:
bool MoveToTarget(pointers& p)
{
WaitForSingleObject(startEvent, INFINITE);
SetEvent(startEvent);
while (IsAlive)
{
p.rocp->GetRealTimeTCoord(p.tarp);
if (p.rocp->x != p.rocp->TX)
if (p.rocp->x < p.rocp->TX)
if (p.rocp->TX < 0)
p.rocp->x++;
else
p.rocp->x++;
else if (p.rocp->x > p.rocp->TX)
if (p.rocp->TX < 0)
p.rocp->x--;
else
p.rocp->x--;
if (p.rocp->y != p.rocp->TY)
if (p.rocp->y < p.rocp->TY)
if (p.rocp->TY < 0)
p.rocp->y++;
else
p.rocp->y++;
else if (p.rocp->y > p.rocp->TY)
if (p.rocp->TY < 0)
p.rocp->y--;
else
p.rocp->y--;
// p.rocp->GetRealTimeTCoord(p.tarp);
// if (p.rocp->x != p.tarp->x)
// if (p.tarp->x < 0) p.rocp->x--;
// else p.rocp->x++;
//
// if (p.rocp->y != p.tarp->y)
// if (p.tarp->y < 0) p.rocp->y--;
// else p.rocp->y++;
cout << "\nMissile at : " << p.rocp->x << " ," << p.rocp->y << endl;
Sleep(500); // <--- Изменить, а то не совсем честно получается - ракета медленно летит
p.rocp->Hit(p.tarp->TStatus);
if (!p.tarp->TStatus)
{
IsAlive = false;
}
}
return true;
}
Кстати, чтобы ракета наводилась на цель, достаточно:
if(p.rocp->x > p.rocp->TX) p.rocp->x -= 1;
else if(p.rocp->x < p.rocp->TX) p.rocp->x += 1;
if(p.rocp->y > p.rocp->TY) p.rocp->y -= 1;
else if(p.rocp->y < p.rocp->TY) p.rocp->y += 1;
// в одном потоке
cout << "hello" << " world" << endl;
// в другом потоке
cout << "wow" << endl;
Про вывод из потоков понятно.НО проблема-то не в выводе,а в том, что ракеты "психует":) по Х летит вверх, по Y вниз,цель игнорирует. У Вас все нормально?..
Missile at : 8 ,-8
missile report: target at 1527825539 : -1916576418
...всё ясно. Забыл присвоить структуре указателей указатель на цель.
Volvo...Огромное спасибо! Я не знаю, что бы я делал без твоих советов!:)
Кстате, кот у тебя на аватарке классный