Из Тишины Александр Яковлев 2011-04-18 05:08:38 http://oreolek.me/ KohanaPHP Трюки и хаки INSTEAD <body> <p>Если вы не знакомы с движком текстовых игр и визуальных новелл INSTEAD, то вы можете прочитать о нём <a href="http://instead.syscall.ru/about/">здесь</a>. Вкратце: это — очень удобный и понятный для программистов движок простых текстовых приключений (квестов). Что важно, он не только удобный, он ещё и легко расширяемый, благо все игры пишутся на Lua. Я не буду описывать, как писать на нём игры. Я буду описывать, как их можно пилить напильником. Любой инструмент познаётся в деле, не так ли? <!--more--></p> <h4>Сценарий 1: предмет+предмет</h4> У игрока есть инвентарь, в инвентаре есть несколько предметов. Стандартное поведение INSTEAD таково: вы щёлкаете на один предмет, затем щёлкаете на другой — так вы применили первый предмет на второй. Чтобы поймать это событие, надо определить обработчик use в первом предмете или used во втором. Но если вы примените второй предмет на первый, то потребуется опять перехватывать уже новое событие. А что, если вы хотите просто комбинировать предметы, без учёта порядка? <p>Пишем хак.</p> <div> <pre><code>cobj = function(v) v.use = function(this,that) return call(this, 'fuse', that); end; v.used = v.use; return obj(v); end</code></pre> Вот так. Теперь достаточно объявлять объекты типа cobj и давать им функцию fuse: <pre><code>rope = cobj{ nam = 'верёвка', inv = function() local response = 'Длинная крепкая пеньковая верёвка.'; return response; end, fuse = function(this, that) if (that == lock) then inv():del(lock); inv():del(rope); inv():add(rope_with_lock); return 'Вы привязываете к концу верёвки замок.' end; end, }</code></pre></div> <h4>Сценарий 2: выдача случайной фразы в описании комнаты</h4> <p>Если сделать описание комнаты функцией, которая будет просто возвращать случайную фразу, то она выполнится лишь единожды и далее будет выдавать то же самое. Чтобы описание всё-таки менялось, надо выводить его не через return функции, а через текстовый буфер — функции p и pn:</p> <div> <pre><code>something = function() ifsen = ' '; response = {'весёлого жука.', 'весёлого динозавра.', 'весёлого людоеда.', 'весёлого жука-людоеда.'}; return ifsen..response[rnd(#response)]; end dinner = room { nam = 'Весёлая столовая', dsc = function() p [[Я вижу]]; p (something()) end };</code></pre></div> <p>Если не поставить скобки после something, то ничего не получится. Так можно получить что-то вроде:</p> <p><a href="/wp-content/uploads/2011/04/a0d76bfd.jpg"><img src="/wp-content/uploads/2011/04/a0d76bfd.jpg" alt="" title="Скриншот из «Игры с разумом»" width="640" height="480" class="aligncenter size-full wp-image-1845"></a></p> <h4>Сценарий 3: новый тип объектов</h4> <p>О, это уже глубокое копание. Допустим, вам нужен новый тип объектов в комнатах. Скажем, вы пишете RPG (можно хоть MMORPG — лишь бы у игрока были библиотеки Lua для работы с сетью), и вам нужен список квестов. Для этого незачем пересобирать движок, достаточно немного покопаться в его Lua части:</p> <div> <pre><code>function quest(v) --constructor if v.nam == nil then error ("Не указано имя квеста.", 2) end if v.short_dsc == nil then v.short_dsc = "" end if v.scene == nil then v.scene = room_scene end if v.completed == nil then v.completed = false end if v.look == nil then v.look = room_look end if v.save == nil then v.save = room_save end v.location_type = true; if v.way == nil then v.way = { } end v.isQuest = true; v.way = list(v.way); v = obj(v); return v; end function room_look(self) local i,n,v,ph for i,o in opairs(self.obj) do if isObject(ref(o)) and not o.isQuest then o = ref(o); if v == nil then v = stead.par(' ',v, o:look()); else v = v .. stead.par(' ',v, o:look()); end end end function room(v) v.location_type = true; if v.look == nil then v.look = room_look end if v.scene == nil then v.scene = room_scene end if v.quests == nil then v.quests = list {} end if v.obj == nil then v.obj = v.quests else for k,m in pairs(v.quests) do v.obj[k] = m end end if v.way == nil then v.way = {} end v = room(v); return v; end </code></pre></div> <p>Сначала мы определяем новый тип объектов — квесты. Это практически копипаст из stead.lua объекта obj, только добавлены поле isQuest, чтобы легче различать квесты и объекты, и добавлено поле completed, которое отвечает за выполнение квеста.</p> <p>room_look - это функция, которая вызывается, когда игрок осматривает комнату. Обычно она выводит описания всех объектов комнаты (из массива obj). Здесь добавлена только заглушка: не выводить описания всех квестов в комнате.</p> <p>Также переопределена сама комната — теперь в ней есть массив quests. Массив obj заполняется объектами из массива quests — приравнивается, если он пуст, и соединяется, если объекты в нём есть.</p> <p>Это просто пример, можно определять любые типы объектов и комнат.</p> <p>Вот. А теперь, когда вы уже знаете несколько хитроумных трюков в этом великолепном движке, можете читать <a href="http://instead.syscall.ru/wiki/ru/gamedev">обычную документацию</a>.</p> </body> keloero@oreolek.me (Александр Яковлев) http://oreolek.me/Post/view/1840 http://oreolek.me/Post/view/1840 Mon, 18 Apr 2011 05:08:38 +0700