В этом уроке вам придется иметь дело с некоторой техникой, такой как заглавные буквы и рифма. Для того чтобы создать хорошую игру, вам потребуется добавить к рецепту талант. Игра, которую вы реализуете, проста. Имеется червь, быстро ползущий по экрану. Игрок должен изменять его направление, для того чтобы предохранить червя от ударов о препятствия и стены. Вам необходимо реализовать следующие элементы:
1. Окно, по которому червь будет ползать. Окно должно иметь три кнопки для управления игрой и четыре кнопки для управления движением червя.
2. Класс состояний, который описывает направление движения и положение червя. Он содержит:
      • предикат init для инициализации червя, т.е. для начального состояния;
      • предикат mov для изменения положения червя;
      • предикат turn, который используется для выполнения поворотов.
3. Класс, который рисует изображение положения червя. Он содержит предикат snapshot(Win). Обратите внимание на следующую деталь: предикат snap-shot не может нарисовать червя прямо в окне. Это бы заставило мерцать изображение. Он должен построить изображение и только затем нарисовать его на экране.
4. Таймер, который вызывает mov и snapshot через фиксированные интервалы, для того чтобы создать иллюзию движения.

Мы знаем, что делать – давайте сделаем это. До этого момента, каждый раз, когда вы создавали класс, вам рекомендовалось снимать галочку Creates Interface. Однако если мы жестко будем следовать этой установке, наша игра будет иметь очень неприятное свойство. Если вы проиграете, выйдете из текущей игры и попробуете начать новую, то обнаружите, что новая игра не находится в исходном состоянии. Вместо этого она будет в последнем состоянии, в котором вы ее оставили. Проблема заключается в том, что переменные, которые используются для описания состояния, имеют память, которая сохраняется от одной формы к другой. Объекты были изобретены для предотвращения такого неприятного поведения. Поэтому давайте используем прекрасную возможность изучить, как создавать объекты и работать с их состояниями.

Для начала создайте проект «game», в поле Project Kind нужно указать MDI. Теперь создадим форму lawn. На ней удалим все кнопки, которые были созданы по умолчанию и добавим необходимые кнопки для нашей игры:
• «Start», рекомендуемое имя (далее Name) «start_ctl»;
• «Stop», Name – «stop_ctl»;
• «Up», Name – «up_ctl»;
• «Left», Name – «left_ctl»;
• «Right», Name – «right_ctl»;
• «Down», Name – «down_ctl».
Постройте приложение, для того чтобы включить в него эту форму. Затем, так же как и в предыдущем уроке включите File > New и добавьте код:

clauses
	onFileNew(S, _MenuTag) :- X = lawn::new(S), X:show().
Для того, чтобы отделить собственно созданные файлы создадим новый пакет playground.

Далее добавим класс objstate внутри playground, не отключая Create Interface. В файл objstate.pro поместите код:

implement objstate

open core, vpiDomains

facts
	w:(integer, pnt) nondeterm. % worm
	d:(integer, integer) single. % direction

clauses
	init() :-
		assert(w(1, pnt(110, 100))),
		assert(w(2, pnt(120, 100))),
		assert(w(3, pnt(130, 100))),
		assert(w(4, pnt(140, 100))),
		assert(w(5, pnt(140, 100))).
	d(10, 0).
	mov() :-
		retract(w(1, P)),
		P = pnt(X1, Y1),
		d(DX, DY),
		P1 = pnt(X1+DX, Y1+DY),
		assert(w(1, P1)),
		retract(w(2, P2)),
		assert(w(2, P)),
		retract(w(3, P3)),
		assert(w(3, P2)),
		retract(w(4, P4)),
		assert(w(4, P3)),
		retract(w(5, _)),
		assert(w(5, P4)), !.
	mov().
	segm(rct(X, Y, X+10, Y+10)) :-
		w(_, pnt(X, Y)).
	turn(DX, DY) :-
		assert(d(DX, DY)).

end implement objstate
Класс objstate должен иметь интерфейс в файле objstate.i:
interface objstate

open core, vpiDomains

predicates
	init:().
	turn:(integer, integer).
	mov:().
	segm:(rct) nondeterm (o).

end interface objstate
Постройте приложение.

Для прорисовки червя создадим класс draw внутри playground. В данном случае отключим Create Interface. В файл draw.cl вставим следующий код:

class draw

open core, vpiDomains

predicates
	snapshot:(windowGDI Win, objstate).

end class draw
А также изменим файл draw.pro:
implement draw

open core, vpiDomains, vpi

class predicates
	draw:(windowHandle, objstate) procedure.

clauses
	draw(W, S) :-
		S:segm(Rectangle),
		vpi::drawEllipse(W, Rectangle),
		fail.
	draw(_W, _S).
	snapshot(Win, S) :-
		S:mov(), !,
		Rectangle= rct(0, 0, 200, 200),
		W= pictOpen(Rectangle),
		draw(W, S), Pict= pictClose(W),
		Win:pictDraw(Pict, pnt(10, 10), rop_SrcCopy).

end implement draw
Постройте приложение для включения класса draw в проект.

Для обработчика ShowListener диалогового окна Properties формы lawn.frm добавим код, который будет создавать объект класса objstate и отображать начальное состояние червя:

class facts
	stt:objstate := objstate::new().

clauses
	onShow(Parent, _CreationData) :-
		stt := objstate::new(),
		stt:init().
Теперь сделаем рабочими наши кнопки. Для этого нужно добавить код для обработчика ClickResponder, соответствующего каждой из кнопок:
facts
	tm: timerHandle := erroneous.
predicates
	onStartClick : button::clickResponder.
clauses
	onStartClick(_Source) = button::defaultAction() :-
		tm := timerSet(500),
		start_ctl:setEnabled(false),
		pause_ctl:setEnabled(true),
		stop_ctl:setEnabled(true).

predicates
	onPauseClick : button::clickResponder.
clauses
	onPauseClick(_Source) = button::defaultAction() :-
		timerKill(tm),
		start_ctl:setEnabled(true),
		stop_ctl:setEnabled(true),
		pause_ctl:setEnabled(false).

predicates
	onStopClick : button::clickResponder.
clauses
	onStopClick(_Source) = button::defaultAction() :-
		timerKill(tm),
		stt := objstate::new(),
		stt:mov(),
		R = rct(10, 10, 210, 210), invalidate(R),
		stt:init(),
		start_ctl:setEnabled(true),
		stop_ctl:setEnabled(false),
		pause_ctl:setEnabled(false).

predicates
	onDownClick : button::clickResponder.
clauses
	onDownClick(_S) = button::defaultAction() :- stt:turn(0, 10).

predicates
	onLeftClick : button::clickResponder.
clauses
	onLeftClick(_S) = button::defaultAction() :- stt:turn(-10, 0).

predicates
	onRightClick : button::clickResponder.
clauses
	onRightClick(_S) = button::defaultAction() :- stt:turn(10, 0).

predicates
	onUpClick : button::clickResponder.
clauses
	onUpClick(_S) = button::defaultAction() :- stt:turn(0, -10).
Также нужно добавить код для обработчиков TimeListener и PaintResponder из диалогового окна Properties формы lawn.frm:
predicates
	onTimer : window::timerListener.
clauses
	onTimer(_Source, _TimerID) :- stt:mov(), R= rct(10, 10, 210, 210), invalidate(R).

predicates
	onPaint : window::paintResponder.
clauses
	onPaint(_Source, _Rectangle, GDIObject) :- draw::snapshot(GDIObject, stt).
Постройте и запустите программу. При выборе пункта меню File > New появится окно с червем. Для начала игры необходимо нажать кнопку Start, соответственно для паузы – Pause. Для того, чтобы начать новую игру достаточно нажать Stop – червь переместится в начальное состояние. Вы можете управлять червем с помощью четырех кнопок.

Улучшение игры остаётся за вами. Вы можете добавить препятствия, например стены. Вы также можете положить маленькие яблоки для питания червя и т.д.

                                                                       << предыдущий | к содержанию >>


 Похожие публикации
2016-06-11 • Просмотров [ 347 ]