Как практически с помощью функций WinAPI нарисовать мячик, который бы двигался горизонтально в прямоугольнике вправо-влево, "отскакивая" от боковых стенок, "пинг-понг" - ?
Что именно вызывает затруднения? Рисуем шарик с помощью Ellipse, сам прямоугольник - Rectangle. Написать программу, которая будет проверять, не выходит ли шарик за пределы прямоугольника, и если выходит - изменить направление движения - не должно составить большой проблемы.
В обычном пейнтбоксе и канвасе это действительно несложно, а вот как применить API сколько литературы не читаю, и бумажной и электронной, найти не могу . . . (((
Так тебе совсем WinAPI-шное приложение надо, без VCL? Ну, тогда так, к примеру:
program Project1;
uses Windows, Messages;
const WM_SETUP = 500;
WinName = 'MainWClass'; R = 5;
var myTimer: THandle; delta: integer; Rec: TRect; posX, posY: integer;
function MainWndProc(Window: HWnd; AMessage: UINT; WParam: WPARAM; LParam: LPARAM): INT_PTR; stdcall; var myDC: HDC; ps: PAINTSTRUCT; begin case AMessage of WM_CREATE: // Создание окна begin myTimer := SetTimer(Window, 0, 1, nil); Result := 0; Exit; end; WM_SETUP: // "Установка" начальных значений begin myDC := GetDC(Window); GetClientRect(Window, Rec); posX := 0; posY := (Rec.Bottom - Rec.Top) div 2; delta := 5; ReleaseDC(Window, myDC); Result := 0; Exit; end; WM_SIZE: // Изменение размеров окна begin PostMessage(Window, WM_SETUP, 0, 0); // Просто вызываем "установку" Result := 0; Exit; end; WM_PAINT: begin myDC := BeginPaint(Window, ps); PostMessage(Window, WM_SETUP, 0, 0); // Тоже "установка" EndPaint(Window, ps); Result := 0; Exit; end; WM_TIMER: // Событие таймера begin myDC := GetDC(Window); // стираем старое изображение шарика SelectObject(myDC, GetStockObject(WHITE_PEN)); Ellipse(myDC, posX - R, posY - R, posX + R, posY + R);
if ((delta > 0) and (posX + delta + R > (Rec.Right - Rec.Left))) or ((delta < 0) and (posX - delta - R < 0)) then delta := -delta; posX := posX + delta;
// и рисуем в новых координатах новое SelectObject(myDC, GetStockObject(BLACK_PEN)); Ellipse(myDC, posX - R, posY - R, posX + R, posY + R); ReleaseDC(Window, myDC); Result := 0; Exit; end; WM_DESTROY: // Уничтожение окна begin KillTimer(Window, myTimer); PostQuitMessage(0); Result := 0; Exit; end; else Result := DefWindowProc(Window, AMessage, WParam, LParam); end; end;
function InitInstance: HWND; begin Result := CreateWindow( PChar(WinName), 'Ping-pong', WS_OVERLAPPEDWINDOW, Integer(CW_USEDEFAULT), Integer(CW_USEDEFAULT), Integer(CW_USEDEFAULT), Integer(CW_USEDEFAULT), 0, 0, hInstance, nil); end;
var hwndMain: HWND; AMessage: msg; begin if (not InitApplication) then begin MessageBox(0, 'Ошибка регистрации окна', nil, mb_Ok) end else begin hwndMain := InitInstance; if (hwndMain = 0) then begin MessageBox(0, 'Ошибка создания окна', nil, mb_Ok) end else begin ShowWindow(hwndMain, CmdShow); UpdateWindow(hwndMain); while (GetMessage(AMessage, 0, 0, 0)) do begin TranslateMessage(AMessage); DispatchMessage(AMessage); end; end; end;
а я в полном шоке от этого кода, совершенно растерялась и вчера даже в эфир не вышла . . . Где взять справочный и учебный материал, который мог бы хоть поверхностно объяснить откуда здесь ноги растут???
Нет, мне пока что это совсем незнакомо. Знаю только в первом приближении интерфейс оболочки Delphi7, основные свойства самых расхожих компонентов и простейшие алгоритмы их взаимодействия. Вот фрагмент вашего кода сразу бросился в глаза и удивил - какие-то сплошные сообщения, а не язык программирования:
while (GetMessage(AMessage, 0, 0, 0)) do begin TranslateMessage(AMessage); DispatchMessage(AMessage);
Хм, но что-то цель не получилось достичь. Прямое обращение к функциям операционки по идее должно дать быструю и эффективную (плавную) работу, а шарик на экране движется явно не лучше, чем если бы я его нарисовала эллипсом в канвасе и закрашивала бы каждый раз при единичном перемещении. Дискретность и дрыганье - те же самые...
сразу бросился в глаза и удивил - какие-то сплошные сообщения, а не язык программирования:
Вот именно это и есть основной цикл обработки сообщений. Перевожу на русский:
пока (есть_сообщения_для_окна) транслировать_сообщение; переслать_сообщение_оконной_функции;
А уже внутри оконной функции (та самая MainWndProc) анализируем, собственно, какое сообщение было получено, и что надо делать в связи с его получением.
шарик на экране движется явно не лучше, чем если бы я его нарисовала эллипсом в канвасе и закрашивала бы каждый раз при единичном перемещении. Дискретность и дрыганье - те же самые...
Тебе записать видео, или ты поверишь, что никакого дерганья я у себя не наблюдаю? И с чем оно связано - не знаю.
Добавлено через 14 мин.
Цитата
шарик на экране движется явно не лучше, чем если бы я его нарисовала эллипсом в канвасе и закрашивала бы каждый раз при единичном перемещении.
Кстати, вопрос на засыпку: с чего ты взяла, что на WinAPI должно быть ЛУЧШЕ? То же самое рисование на канвасе, то же самое перемещение (только не единичное, а 5-ти единичное, что может послужить причиной "дерганья", нет DoubleBuffered, что тоже не улучшает визуализацию). Ты меня извини, конечно, но писать здесь полный код, работающий идеально, я считаю нецелесообразным. По нескольким причинам. Главная из которых - если тебя ЭТО уже вводит в ступор, то я представляю, куда тебя введет более сложный код.
Цитата
что-то цель не получилось достичь
Целью было написание приложения, перемещающего изображение мяча горизонтально, от одной стенки к другой. Про плавность перемещения и его идеальность речи не было. Если тебя это не устраивает - делай сама, больше мешать тебе своими постами не буду.
Владимир, прямое обращение к функциям ОС меня заинтересовало потому что Вы здесь на форуме утверждали, что это принципиальная экономия тактов и загрузки процессора, а следовательно и увеличение быстродействия программы. Использовать WinAPI правильнее, чем пытаться оптимизировать алгоритмы в графических VCL. Теперь буду пытаться разобраться, на каком этапе возникает дискретность анимации. В моем варианте мячик пинг-понга движется с видимыми хотя и незначительными рывками примерно одинаково что в канвасе пейнтбокса, что в нарисованном Вами консольном поле. Процессор Core Duo Pro с соответствующей тактовой частотой, на который грех жаловаться, другие программы отключены, резидентно висит только самый необходимый минимум. И очень огорчаюсь, если Вас чем-то ненароком обидела ..
Дерганье и правда присутствует, даже не дёрганье, а перемещение мячика как бы маленькими рывками. Это хорошо заметно, если поставить интервал таймера равным 500, например. Но для учебных целей этого более чем достаточно, по моему:) На WinAPI вроде бы программы ещё маленькие получаются...
--------------------
"Знаешь, стыдно - когда не видно, что услышал всё, что слушал.."