Как написать игру на lazarus

О разработке небольшой игры с помощью Lazarus После относительно недавнего релиза Lazarus 1.0, захотелось опробовать эту IDE на практике. Так появилась идея написать игру. Из основных требований — она должна быть несложной, с небольшими затратами времени на ее реализацию. Ну и конечно же, ее написание и сам геймплей должны быть достаточно увлекательными процессами, даже для меня как ее создателя.
Что ж, пожалуй лучшим способом добиться поставленных целей, являться высокий уровень случайности, что бы параметры и поведение игры было трудно точно спланировать. Ну и конечно спонтанность в разработке, когда наперед ничего конкретного не планируется.

Итак, начало вполне стандартное. А именно пустая форма в среде Lazarus:
О разработке небольшой игры с помощью Lazarus

Все довольно скучно и серо. Не помешало бы добавить каких то красок. После 20 минут создания классов и вспомогательных классов, получилось нарисовать несколько деревьев и водоёмов (вид сверху):

О разработке небольшой игры с помощью Lazarus

Вероятно, у многих возникнет вопрос, почему деревья квадратные, а водоёмы прямоугольные… ответ весьма банален — все выполнено в новомодном метро стиле. Вполне возможно, что так бы и выглядели настоящие деревья, если бы их дизайном занимались ребята из Microsoft.
Вдоволь насладившись открывшимся пейзажем, начинаешь замечать, что в нем чего-то не хватает. Да, пожалуй отсутствие динамики делает наблюдение за новосозданным миром весьма скучным занятием. Здесь и появилась мысль добавить элемент хаоса и непредсказуемости — жизнь. Или вернее примитивных живых существ. Итак, пускай они будут круглые, да еще и двух видов — синие и красные. Их бесцельное слоняние по миру создаст достаточно динамики. Ну и что бы было поинтересней, надо продумать механизм их размножения. Хотя с этим все просто — если синий кружочек пересечется с красным — возле них появиться новый кружочек. Что-то это напоминает, ну да ладно. И снова приступаем к созданию классов и их наполнением. После нескольких сотен строчек кода, удалось добиться поставленной задачи — кружочки спокойно ползали около квадратных деревьев и весьма успешно размножались.

О разработке небольшой игры с помощью Lazarus

Даже более чем успешно — в определенных местах, где количество случайных пересечений было велико — данные существа умудрялись размножаться в геометрической прогрессии, занимая собой все свободное пространство и заставляя мой ноутбук довольно шумно жужжать. Таким образом, их популяция достигала несколько сотен тысяч всего за несколько секунд.

О разработке небольшой игры с помощью Lazarus

Визуально это напоминало размножение какого-то вируса в чашке Петри. Дальше дело так продолжаться не могло, так что были придуманы некоторые дополнительные параметры для существ. Теперь существа имели ограниченный строк жизни (LifeTime:integer). Также как и необходимость «отдохнуть» после размножения (ReprodDelay:integer), кроме того, был добавлен параметр скорости передвижения (Speed:single). Все эти переменные были запихнуты в структуру RGenes, которая заполнялась случайными параметрами для каждого отдельного существа при старте программы. Ну а при появлении нового существа, его параметры заполнялись среднеарифметическими значениями, взятыми у его родителей. При таком подходе, появился весьма занимательный эффект — после нескольких поколений, средние параметры популяции возрастали на несколько процентов. Получалось, что существа с большим LifeTime и меньшим ReprodDelay, лучше выживали и давали лучших потомков. Закон естественного отбора просматривается даже при таких примитивных условиях. Здесь также подумалось, что при случайном (или не очень) появлении примитивных живых клеток (первых признаков жизни), самым сложным являться процесс воссоздания копии этих же клеток, тогда как наделением их питательными веществами и созданием движения вполне может заниматься подходящая неживая окружающая среда.
После проделанных манипуляций получился довольно занятный мирок, в котором ползали кружочки и занимались своими делами. Впрочем, захотелось большего. Так в исходный код попал класс TPlayer и еще несколько сотен строчек кода, которые отвечали за создание, прорисовку и движение серого кружочка которым игрок должен управлять. При пересечении игроком каких либо существ, у него отнимается здоровье. Когда здоровье становиться равным 0, считается что игра закончена. В водоёмах здоровье восстанавливаться. Все это конечно интересно, но стоит также дать игроку возможность как-то защищаться. Для этого хорошо подойдут… башни, которые можно строить недалеко от серого кружочка (радиус строительства прорисовывается на карте) и которые будут уничтожать нахальных существ, проползающих мимо. Все, теперь с помощью левой кнопки мышки (либо стрелками на клавиатуре), можно передвигаться по карте, а правой кнопкой ставить башни для уменьшения популяции вредных существ. Строительство башни требует некоторых расходов очков, которые зарабатываются уничтожением существ. Чтобы не блуждать просто так, было добавлено некоторую финальную цель — собрать 40 энергетических ячеек разбросанных по карте. Каждая ячейка улучшат характеристики игрока (желтая — скорость, фиолетовая — жизнь, голубая — радиус для постройки башень). Но следует быть осторожным — кроме улучшения характеристик, увеличивается цена на строительство башни.
Получилась довольно занятная игра в стиле… можно сказать tower attack, так как башни строятся не столько для защиты, сколько для нападения.

О разработке небольшой игры с помощью Lazarus

Несколько слов о внутренней структуре игры

Карта игры составляет поле размером 4500*4500 пикселей. Начальная популяция существ, насчитывает около 5000 особей. Со временем, они конечно размножаются хотя максимальное их количество установлено в 30 000, что довольно много. Для упрощения расчетов, карта разбивается на ячейки размером 32*32 пикселя. В ячейке храниться информация о том, какие игровые объекты в текущий момент времени находятся в ней. Такой подход позволяет сделать достаточно эффективные прорисовки (для прорисовки перебираются только те объекты, которые находятся в видимых ячейках карты), а также относительно быстро просчитывать пересечение игровых элементов даже при их огромном количестве (все пересечения просчитываются в пределах ячейки к которой они принадлежат).

Несколько слов о Lazarus

Пожалуй, саму Lazarus можно рассматривать как возможность замены Delphi на бесплатную кросплатформеную open source IDE, с возможностью компиляции программ под разные ОС (Windiws x86/x64, Linux, Mac OS X). Визуально Lazarus повторяет старые версии Delphi, так что если вы работали в Delphi 7, то интерфейс вам будет вполне знакомым. Лично мне подобная оконная система никогда не нравилась — слишком много места используется не эффективно, к тому же сложно поддерживать порядок, особенно когда открыто с десяток мелких окошек, впрочем, в следующих билдах обещали добавить док менеджер (хотя уже сейчас эту ситуацию можно исправит с помощью дополнительных модификаций). Отдельно стоит упомянуть редактор кода — он, пожалуй, выполнен вполне на уровне последних версий Delphi, в некоторых случаях даже превосходя их. Встроенный помощник работает довольно шустро, к тому же на этом проекте не было ни одного ложного перехода между declaration/definintoin (ctrl+click, ctrl+shift+up, ctrl+shift+down). К примеру, Delphi 2010, XE у меня регулярно ошибались в переходах, даже на относительно небольших проектах. В целом, переходя на Lazarus скажем с Delphi 7 (на нем до сих пор много программистов пишут программы) вы можете получить не только более удобную IDE с кросс-платформенной компиляцией, но и современные синтаксические возможности самого языка, например перегрузку операторов и дженерики.
Не обошлось и без ложки дегтя. Debugger в Lazarusе жутко неудобный. Переход между строчками (F7, F8) не самый шустрый (отладка это процесс вдумчивый, спешить особо некуда), хотя хуже всего просмотр значений переменных. Если вас интересуют простые типы, то с этим проблем нет, в окошке watches их спокойно можно просмотреть. Массивы, отображаются не полностью, кроме того, массив классов будет отображаться просто как массив указателей (как и классы внутри классов). Если вам нужно просмотреть что-то глубже, тогда можно прописать путь к переменной в окошке Evaluate/Modify (которое открывается в единственном экземпляре). Просмотр переменных передвигаясь по call-stackу также не возможен. Учитывая все это, отладка сложного кода превращается в довольно утомительный и длительный процесс. На официальной страничке вики пишут, что над дебагером ведутся работы, так что есть надежды, что в следующих билдах все будет на порядок удобнее.
Перенести код с Delphi не составляет особых трудностей — синтаксис языка почти полностью повторяет делфийский, изменений не тук уж и много (wiki), хотя при конвертации текстовых переменных могут быть нюансы: (wiki). Если кто помнит мой предыдущий топик, о программной работе с клавиатурой в Delphi, то выложенный там проект удалось успешно скомпилировать под Лазарусом после небольших правок, которые заняли мене 5 минут. Это при том, что код взаимодействует с системой Windows посредством Low Level хуков (которые, к примеру, не возможны с .NET среды) и имеет много завязок на API Windows.
Так как при разработке игры интересовали нативные возможности написания ПО, то для прорисовки игровых элементов использовались стандартные возможности рисования по canvas. К сожалению, финальная скорость прорисовки ниже чем в делфийских программах, так что если вы хотите работать с графикой в Lazarus, надо быть готовым к использованию сторонних компонентов. Впрочем, с этим нет никаких проблем (wiki). Имеются даже готовые игровые движки.

Эпилог

Сами исходники игры можно скачать здесь, а скомпилированную игру под Windows здесь.

Надеюсь, эта статья сможет помочь начинающим игростроителям демонстрируя что при правильном подходе, процесс разработки игры не только не сложен, но и может быть весьма увлекательным.

Автор: Corwal

Практическая работа «Пазл»

Автор: Кочергина Кристина Николаевна, педагог дополнительного образования МУДО «Сланцевский ЦИТ»

  1. Создать новый проект и сохранить его в отдельной папке.

  2. Придать форме название Практическая работа «Пазл».

  3. На форму добавить компонент Image с закладки Additional. В свойстве Picture компонента Image выбрать нужный рисунок. Свойство Proportional со значением true изменяет размер загруженной картинки в соответствии с размерами компонента. При необходимости растянуть компонент, чтобы был виден весь рисунок.

  4. Добавить нужное количество компонентов Image и настроить их свойства согласно таблицы. Все компоненты Image должны иметь одинаковые размеры, совпадающие с картинкой.

Компонент

Свойства

Описание

Форма

Рабочая область программы

Image1

  1. , загрузить изображение в компонент

  2. , картинка примет размеры компонента

Пример изображения, который надо собрать

Image2

Image3

Image4

Image5

  1. , загрузить фоновое изображение в компонент

  2. , картинка примет размеры компонента

Область состоящая из 4 изображений, в которые загружены одинаковые картинки. В этой области собирается пазл

Image6

Image7

Image8

Image9

  1. , загрузить фрагмент пазла в компонент

  2. , картинка примет размеры компонента

4 изображения, из которых собирается пазл. Эти изображения можно перетаскивать левой кнопкой мыши

Button1

Кнопка сброса настроек, позволяет начать собирать пазл с начала

  1. Добавить кнопку Начать заново, щелчок по которой возвращает все изображения пазла на место. Для того в событиях этого компонента щелкнуть по событию OnClick и написать следующий код

procedure TForm1.Button1Click(Sender: TObject);

begin

Image6.Visible:=true; // сделать видимым компонент Image отвечающего за картинку пазла

Image7.Visible:=true;

Image8.Visible:=true;

Image9.Visible:=true;

Image2.Picture.LoadFromFile(‘фон.jpg’); // загрузить в компонент Image изображение фона

// пазла

Image3.Picture.LoadFromFile(‘фон.jpg’);

Image4.Picture.LoadFromFile(‘фон.jpg’);

Image5.Picture.LoadFromFile(‘фон.jpg’);

end;

  1. В компоненте Image2 в событие DragDrop написать следующий код:

procedure TForm1.Image2DragDrop(Sender, Source: TObject; X, Y: Integer);

begin

(Sender as TImage).Picture:=(Source as TImage).Picture;

// свойство Picture компонента Image, в который помещается перетаскиваемый

//фрагмент пазла, принимает значение перетаскиваемого изображения

(Source as TImage).Visible:=false; // компонент Image, который перетаскивается в

//данный момент, становиться невидимым

end;

Во всех остальных компонентах Image, которые отвечают за область готового пазла, т.е. Image3,4,5 в событие DragDrop сослаться на компонент для которого написан код, т.е. в нашем случае на Image2

  1. В одном из компонентов Image, которые отвечают за область готового пазла, в событие DragOver написать следующий код:

procedure TForm1.Image2DragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean);

begin

Accept:=true; // разрешить принимать компонент, который перетаскивается

end;

Во всех остальных компонентах Image, которые отвечают за область готового пазла, т.е. Image3,4,5 в событие DragDrop сослаться на компонент для которого написан код, т.е. в нашем случае на Image2.

Projects using
Free Pascal

Business Software
Communications software
Components and Libraries
Databases and Tools
Developer utilities
Editors and IDEs
Educational software
Games
Hobby software
Medical and Scientific software
Multimedia
User utilities
Web

15-puzzle

15-puzzle is a sliding puzzle that consists of a frame of numbered square tiles in random order with one tile missing. The object of the puzzle is to place the tiles in order by making sliding moves that use the empty space.

puzzle15.png

2048

2048 is a Lazarus implementation of famous block sliding puzzle video game.

2048.png

BigMetro

BigMetro is metro building game inspired by MiniMetro game. Runs on Windows, Linux and macOS (need to compile yourself for macOS).

BitMetro small.png
BigMetro main.png

Bomber Kat

Commercial game developed with FPC for iOS (both arm and arm64 platforms are supported). ZenGL based. Lazarus has been used as a primary IDE. Link: App Store

C-evo: New Horizons

C-evo: New Horizons is a fork of the well designed turn-based empire building game C-evo inspired by Civilization II game. It was originally developed for Windows using Delphi 4 but later fully porter to Lazarus to support also Linux.

C-evo start.png
C-evo game.png
C-evo game2.jpg

Castle Game Engine

Castle Game Engine (project page) is a 3D open-source game engine. The engine was developed from the beginning using Free Pascal (we have also Lazarus components) in nice and clean ObjectPascal code. We support many 3D model formats, including VRML/X3D, Collada, 3DS and many others. Tools and games using the engine include:

  • view3dscene — 3D model viewer, VRML/X3D browser,
  • The Castle — FPS game in a dark fantasy world,
  • Darkest Before the Dawn — small scary 3D game for standalone and Android (also on Google Play)

Common Loon Hearts

Common Loon Hearts is the card game Hearts. It is written in Free Pascal with the Lazarus IDE for Windows and Linux. Source code is available here.

hearts screen.png

DMines

DMines is an edition of the classic game Minesweeper with a dynamic twist, unrevealed mines can change location every set number of seconds.

DMinesExample.jpg

Dreams of a Geisha

Take a journey through the magical and wonderful world of Geisha. Help Ichisumi in this incredible adventure to reopen the temples of Geisha and restore a world of beauty and passion. Dive into this engaging Match 3 game with beautiful scenery and relaxing music. Overcome obstacles, collect puzzle pieces, and be prepared to solve challenging puzzles in Dreams of a Geisha!

Powered by Lazarus FPC, ZenGL, PhoenixLib, LUA and TexturePacker. Developed by Green Sauce Games and Released by Big Fish Games.

Demo available for Windows, Mac, iPhone, iPad.

Dreams of a Geisha - Screenshot 1.jpg

Eschecs

Eschecs is an application to play chess against different artificial opponents. Eschecs uses the fpGUI Toolkit, and the uos and BGRABitmap libraries.

eschecs500f.png

Fairtris

Fairtris is a video game, a clone of the 32-year-old Tetris® game produced by Nintendo for the Famicom and NES consoles, designed for modern Windows systems. Fairtris is not an emulator — it is a full-fledged game with OpenGL support via the SDL library (using the SDL2-for-Pascal headers). Thanks to this combination, it is super-fast and ultra-light. This project was initially created as a tool to test various RNG algorithms, but after some time it turned into a complete and rich video game and a knowledge base for those who would like to know more about the internal mechanisms of the classic version of this game. For more information, see the project wiki on GitHub.

Important features:

  • implementation of gameplay mechanics compatible with the Nintendo Tetris® game,
  • DAS mechanics fixed and spin buffering added, making the controls fabulously responsive,
  • extended mechanics with basic wall kick, hard-drop and multi-spawn soft-drop,
  • support for eight regional versions of the game, including original NTSC and PAL versions,
  • support for as many as seven random piece generators, including the classic RNG,
  • support for free marathon and speedrun modes, qualifications and matches with same piece set,
  • the ability to start the game from any level up to the killscreen,
  • the ability to play on a keyboard or any USB controller (with input mapping support),
  • supports window mode and exclusive video mode,
  • support for additional meters, such as TRT, BRN, as well as gain popup,
  • stores the best results for each game region and RNG type,
  • has a pause menu with the ability to quickly restart the game and change settings,
  • shows the game summary screen after each game,
  • support for two themes (minimalistic dark and classic skin),
  • possibility to use it with NestrisChamps and MaxoutClub,
  • it’s light and very fast — should run smoothly even on a heavily loaded PC,
  • it is fully portable, no installation required,
  • and many more!

Fairtris prime menu.png
Fairtris gameplay.png
Fairtris prime menu 2.png
Fairtris gameplay 2.png

fpChess

fpChess is still under construction. It should support playing via the internet as well as against a computer AI.

Fpchess.png

Game Maker

Game Maker allows you to make computer games using easy to learn drag-and-drop actions. You can create professional looking games within very little time. You can make games with backgrounds, animated graphics, music and sound effects, and even 3D games! And when you’ve become more experienced, there is a built-in programming language, which gives you the full flexibility of creating games with Game Maker. What is best, is the fact that Game Maker can be used free of charge.

Originally written in Delphi, Lazarus/Free Pascal was used to port it from Win32 to macOS. Available for Windows desktop, macOS, Ubuntu, Android, iOS, tvOS, fireTV, Android TV, Microsoft UWP, HTML5, PlayStation 4, and Xbox One.

Hedge Wars

Hedge Wars is a worm-like game with very nice graphics and good AI. The game features typical worms gameplay including net play. The game itself is written in FPC while the config application is C++/Qt.

HedgeWars Scene

JavaneseChess

JavaneseChess is a Javanese chess game implementation. Available for Desktop platforms and Android (not feature complete yet).

Juegos Iniciales

Juegos Iniciales are a small collection of 3D tutorial games in
Lazarus, SDL and Free Pascal. In 2016, there were only four games:
Origamis Iniciales,
Bloques Iniciales,
Nudos Iniciales,
Palitos Iniciales.

LazGobang

LazGobang is a Gobang game, powered by Lazarus and Free Pascal.

Lazarus Mazes

The Lazarus Mazes program is a demonstration of how you can use Lazarus to create a maze. The maze generation is based on a depth-first backtracking algorithm. As a bonus, a simple maze solver is also implemented that shows a route from the start of the maze to the exit.

mazedemo1.png

LBP Level Logger

LBP Level Logger is a small system tray application designed to log LittleBigPlanet level statistics from lbp.me over time for graphing/visualisation. It is written in Free Pascal/Lazarus.

lbplevellogger-screenshot.png

Lentil Wars

Lentil Wars is an arcade action game for Linux and Windows that is still under development. Players combat each other in multiple nicely designed levels. Lentil Wars can be played both on a single computer as well as over a network.

Lentil Wars Scene

Mundo Medieval 3D MMORPG

Featuring a virtual world of more than 1.000.000 m2, plus caves and hell sceneries, 17 NPCs, 21 kinds of monsters, including 7 bosses, 58 different items and 100 quests, this is a really large game made with Free Pascal/Lazarus. The project is 100% free software, both code and media are licensed under GPL. The project sites are http://www.gamemundo.com/ and http://sourceforge.net/projects/gamemundo/.

Mundo - Screenshot 1.png
Mundo - Screenshot 2.png
Mundo - Screenshot 3.png

Peg Solitaire tutorial

Peg Solitaire serves as a game (Peg Solitaire) tutorial that aims at introducing the user to the basics of Lazarus application development. Source available.

tutpeg solitaire.png

Petris

Petris is yet another Tetris clone. Source available.

petris.png

Retro Ski Run

Retro Ski Run is a simple ski game for Windows 32/64bit and Linux 32/64-bit.

ss rsrStartScreen.jpg

Robot — The Game

Robot is a game in which you control a character through a world consisting of 5*5 rooms, each with 20*20 fields. Every field contains a special game object; this can be a wall, a bad robot who wants to kill you (because of the robots, the game is named Robot), a door (for each door, you need a special key) and so on. and examples/Robot 1.7/ Source available.

robot1.5-shot1.png

Snake for ptcGraph

Snake for ptcGraph is a simple snake game based on the ptcGraph unit. Steer the snake with keyboard arrows and eat as many fruits as you can.

snake2.png

UltraStar Deluxe

UltraStar Deluxe is a free and open source karaoke game inspired by the Singstar™ game available on the Playstation®. It allows up to six players to sing along with music using microphones in order to score points, depending on the pitch of the voice and the rhythm of the singing. It is currently available for Windows, Linux, macOS and FreeBSD.

UltraStar Deluxe Main Page

ValisoaChess

ValisoaChess is a chess game written in Free Pascal and Lazarus. The main goal is to create a simple yet powerful chess engine.

valisoachess.jpg

Zen GL updated

Zen GL is a 2D game engine. Now Zen GL uses Steam Game Libraries. You can migrate your Delphi X or Image Sprite old 2D Delphi games with that Zen GL upgraded Game Engine. The Zen GL Linux packages are zgl.deb or zgl.rpm.

And also an updated version of ZenGL with support for Android and MacOS Cocoa. In Russian. Support for English is evolving. Inside there is a link to the iOS version but the new features are not included.

Время на прочтение
7 мин

Количество просмотров 14K

Вместо предисловия

В одесской школе ученики 8-го класса на уроках информатики используют бесплатную кроссплатформенную среду разработки Lazarus (официальный сайт), внешне и внутренне очень напоминающую любимый многими Delphi, использующую версию Object Pascal под названием Free Pascal и в действительности сильно упрощающую процесс вхождения в программирование.

Но детям неинтересно писать программу для вычисления силы тяжести по непонятной им пока формуле F=mg. Практически все дети, которых я пытался учить программированию, с первого занятия хотят написать игру. К счастью, Lazarus прекрасно подходит и для написания несложных игр.

Правда, для создания анимированных спрайтов мне понадобился компонент, отображающий произвольный фрагмент изображения (на котором изображены несколько разных проекций одного и того же персонажа в разных фазах движения), а такого компонента в стандартной поставке нет. Написать его самому оказалось совсем несложно, и об этой технологии я и хочу рассказать в этой статье.

Для отображения веселого графического контента вместо сухого делового набора стандартных компонентов в Lazarus (как и в Delphi) есть 3 компонента на вкладке Additional:
— TImage (отображение картинки из произвольного файла);
— TShape (отображение одного из нескольких заранее заданных графических примитивов);
— TPaintBox (отображение холста, на котором можно рисовать программно).

Самое эффектное для школьника — загрузить небольшой спрайт в TImage и написать программу для перемещения его по экрану — по событиям мыши/клавиатуры, автоматически в цикле или автоматически по событию от таймера.

Как только это начинает работать, у школьника возникает следующий законный вопрос: а нельзя ли сделать так, чтобы персонаж двигался? И можно ли сделать сделать так, чтобы он смотрел не постоянно на нас, а поворачивался в сторону, совпадающую с направлением движения?

В Сети можно найти большое количество готовых изображений для использования при разработке игр. И многие персонажи заранее разработаны в несколько проекций и несколько кадров анимации (как, например, вот на этом сайте).

Вот пример изображения, где спрайты расположены в виде таблицы, у которой каждая строка соответствует определенной проекции, а каждый столбец — определенной фазе анимации:

Зачем так много картинок?

Для отображения такого спрайта достаточно поместить на экран простой компонент, отображающий не все изображение целиком, а только один его фрагмент; и затем, меняя смещение выделенного фрагмента по горизонтали и вертикали, можно заставить персонаж поворачиваться в разные стороны и совершать циклические движения (например, махи крыльями или шаги ногами). Такой прием часто используется при веб-разработке: даже простые наборы иконок для деловой графики часто размещают в одном файле и отображают в разных местах страницы с разным смещением, создавая впечатление разных изображений.

К сожалению, компонент TImage, входящий в стандартную поставку Lazarus (и Delphi), не позволяет показывать произвольный фрагмент изображения: изменяя его свойства, мы можем заставить его показывать только изображение целиком, левый верхний угол или центральную его часть. Для отображения произвольного фрагмента изображения, заданного смещением и размерами по обеим осям, нужен какой-то другой компонент. Но, как выяснилось, сделать его самостоятельно в Lazarus — совсем несложно!

Создаем новый компонент

В качестве инструкции по созданию компонентов я воспользовался официальным руководством.

Там все написано достаточно подробно, дублировать не имеет смысла. Я только остановлюсь на некоторых моментах.

1. Стандартный Project Wizard не предлагает нам создать package, и чтобы как-то получить доступ к редактору, выбираем «New Project» (в русской версии — «Новый проект»)

и затем «Application» (в русской версии — «Приложение»):

2. Действуя далее по инструкции, в меню «Package» (в русской версии — «Пакет») выбираем верхний пункт «New package…» (в русской версии — «Новый пакет…»), выбираем имя файла и путь для сохранения. Я назвал свой новый пакет «Game» и разместил его в отдельной папке с тем же названием:

Я создал отдельную папку Lazarus/Cmp в расчете на то, что у меня может появиться несколько разных пакетов с компонентами, и уже в этой папке создал папку «Game».

Если все сделано правильно, на экране должно появиться окно нового (пока пустого) пакета.

3. Действуя дальше опять же по инструкции, для создания нового компонента в окне пакета нажимаем кнопку «Add» (в русской версии — «Добавить») и в выпадающем списке выбираем «New Component» (в русской версии — «Новый компонент»):

В качестве класса-предка указываем TCustomImage — этот класс фактически используется для реализации компонента TImage, но отличается от него тем, что не содержит published properties и позволяет нам самим определить набор свойств, который будет доступен в дизайнере для нашего компонента.

Что такое published properties?

Для тех, кто этого не знает, уточню, что published — это раздел класса (наподобие public), в котором описываются новые или просто указываются унаследованные свойства, которые должны быть доступны в визуальном редакторе свойств на этапе разработки программы. Промежуточные классы не объявляют ничего в этой секции, оставляя возможность программисту самому вынести туда то, что он сочтет нужным. Так, класс TImage не добавляет никакой функциональности, а только помещает в раздел published ряд свойств, унаследованных от родителя TCustomImage. Часть из этих свойств нам нужно спрятать, поэтому мы также унаследуем наш новый компонент от TCustomImage и выведем в published только то, что не противоречит логике нашего компонента.

Пиктограмма (иконка) для компонента

Хорошим стилем было бы рисовать персональную иконку для каждого нового компонента, но так как наша задача — показать, как это все просто, мы оставим это поле пустым, что приведет к отображению на панели инструментов стандартной иконки, используемой в Lazarus/Delphi для всех самодельных компонентов.
Кстати, упомянутая выше инструкция содержит отдельный раздел, посвященный созданию иконок для компонентов — это для тех, кого не устраивает «дефолтная» иконка.

Заполнив все поля, нажимаем кнопку «Create New Component» (в русской версии — «Создать новый компонент»).

Добавляем код в новый компонент

Сразу после создания нового компонента его исходный код получается примерно таким:

unit ImageFragment;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs;

type
  TImageFragment = class(TCustomImage)
  private

  protected

  public

  published

  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Game', [TImageFragment]);
end;

end.

Как и следовало ожидать, объявление класса абсолютно пусто, а имплементация вообще отсутствует. Все, что есть — функция регистрации компонента на вкладке «Game».

Нам нужно добавить несколько унаследованных published properties, создать два своих и переопределить одну виртуальную функцию. Приступим!

0. В секции импорта нам понадобятся два дополнительных модуля: ExtCtrls и LCLProc — добавляем их в раздел uses:

uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, ExtCtrls, LCLProc;

1. Добавляем список published properties, полностью аналогичный компоненту TImage, за исключением нескольких properties, позволяющих изменить масштаб и позицию изображения:

  published
    property AntialiasingMode;
    property Align;
    property Anchors;
    //property AutoSize;
    property BorderSpacing;
    //property Center;
    //property KeepOriginXWhenClipped;
    //property KeepOriginYWhenClipped;
    property Constraints;
    property DragCursor;
    property DragMode;
    property Enabled;
    property OnChangeBounds;
    property OnClick;
    property OnDblClick;
    property OnDragDrop;
    property OnDragOver;
    property OnEndDrag;
    property OnMouseDown;
    property OnMouseEnter;
    property OnMouseLeave;
    property OnMouseMove;
    property OnMouseUp;
    property OnMouseWheel;
    property OnMouseWheelDown;
    property OnMouseWheelUp;
    property OnPaint;
    property OnPictureChanged;
    property OnPaintBackground;
    property OnResize;
    property OnStartDrag;
    property ParentShowHint;
    property Picture;
    property PopupMenu;
    //property Proportional;
    property ShowHint;
    //property Stretch;
    //property StretchOutEnabled;
    //property StretchInEnabled;
    property Transparent;
    property Visible;
  end;

Для пущей убедительности я не удалил, а закомментировал те properties, которые есть в компоненте TImage, но будут мешать в нашем новом компоненте TImageFragment.

2. Добавляем в объявление класса два новых properties для задания смещения изображения по горизонтали и по вертикали:

  private
    FOffsetX: Integer;
    FOffsetY: Integer;
    procedure SetOffsetX(AValue: Integer);
    procedure SetOffsetY(AValue: Integer);
  published
    property OffsetX: Integer read FOffsetX write SetOffsetX default 0;
    property OffsetY: Integer read FOffsetY write SetOffsetY default 0;

и не забываем добавить в имплементацию класса две объявленных процедуры:

implementation

procedure TImageFragment.SetOffsetX(AValue: Integer);
begin
  if FOffsetX = AValue then exit;
  FOffsetX := AValue;
  PictureChanged(Self);
end;

procedure TImageFragment.SetOffsetY(AValue: Integer);
begin
  if FOffsetY = AValue then exit;
  FOffsetY := AValue;
  PictureChanged(Self);
end;

3. Переопределяем виртуальную функцию DestRect:

  public
    function DestRect: TRect; override;

и добавляем ее реализацию в имплементацию класса:

function TImageFragment.DestRect: TRect;
begin
  Result := inherited DestRect();
  if (FOffsetX <> 0) or (FOffsetY <> 0) then
    LCLProc.OffsetRect(Result, -FOffsetX, -FOffsetY);
end;

Компилируем пакет и пересобираем Lazarus

1. В окне пакета нажимаем кнопку «Compile» (в русской версии — «Компилировать»). Если все сделано правильно, в окне сообщений появится зеленая надпись об успешной компиляции, если нет — надпись будет желтой или красной.

2. В том же окне нажимаем на кнопку «Use» (в русской версии — «Использовать») и в выпадающем меню выбираем второй пункт «Install» (в русской версии — «Установить»). Программа предложит пересобрать и перезапустить IDE — соглашаемся:

3. После перезапуска на панели инструментов появится новая вкладка «Game», а на ней — иконка для нашего нового компонента.

Вместо послесловия

В следующей статье Lazarus — простая анимация при помощи компонента TImageFragment я рассказал, как можно использовать такой компонент — за 5 минут создать окно, в котором анимированный персонаж будет двигаться в разные стороны и поворачиваться в сторону направления движения.

Если тема окажется интересной читателям, я могу дополнить этот цикл статьей о том, как, потратив чуть больше времени, можно сделать, к примеру, футбольное поле с парой футболистов, управляемых с клавиатуры.

А если хватит времени и желания — попробую написать разные алгоритмы управления персонажами (например, футболистами) и устроить между ними соревнования!

Мишка Косолапый :)

284 / 254 / 86

Регистрация: 15.02.2012

Сообщений: 1,511

1

Как сделать игру «Пятнашки»?

22.05.2012, 20:16. Показов 8670. Ответов 10


Мне бы посоветовать как сделать игру «пятнашки», а то не пойму как её делать… Как определить в какой квадратик тыкнул.. как переставлять и т. п.

Добавлено через 6 часов 16 минут
Тема вверх!
Люди помощь))



0



Programming

Эксперт

94731 / 64177 / 26122

Регистрация: 12.04.2006

Сообщений: 116,782

22.05.2012, 20:16

10

volvo

Супер-модератор

Эксперт Pascal/DelphiАвтор FAQ

32464 / 20955 / 8108

Регистрация: 22.10.2011

Сообщений: 36,224

Записей в блоге: 7

24.05.2012, 12:07

2

Цитата
Сообщение от zuxa-zuxa
Посмотреть сообщение

Люди помощь))

Сделай на форме 16 Panel-ей (либо вручную, либо создай их при старте формы динамически, главное — чтобы номера контролов были слева направо и сверху вниз, т.е, так как у тебя на рисунке, от Panel1 до Panel16), и назначь им свойства Tag и обработчик клика, а Caption сделай случайным:

Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
procedure TForm1.FormCreate(Sender: TObject);
var
   i : Integer;
   Unused : set of byte;
   X : Byte;
begin
   Randomize;
   Unused := [1 .. 15];
   for i := 1 to 16 do
   begin
      with FindComponent(Format('Panel%d',[i])) as TPanel do
      begin
         Tag := i - 1;
         if Unused <> [] then
         begin
            repeat
               X := Random(15) + 1;
            until X in Unused;
            Exclude(Unused, X);
            Caption := IntToStr(X);
         end;
         OnClick := @MyPanelClick;
      end;
   end;
end;
 
procedure TForm1.MyPanelClick(Sender: TObject);
var
   C, R : Integer;
   Panel : TPanel;
 
   function Find(C, R : Integer) : TPanel;
   begin
      Result := FindComponent(Format('Panel%d',[4 * R + C + 1])) as TPanel;
   end;
   function Is_Empty (C, R : Integer) : Boolean;
   begin
      Result := (Find(C, R).Caption = '');
   end;
   procedure Exch (C, R : Integer);
   begin
      Find(C, R).Caption := Panel.Caption;
      Panel.Caption := '';
   end;
 
begin
   Panel := Sender as TPanel;
   R := Panel.Tag div 4;
   C := Panel.Tag mod 4;
   if (C > 0) and Is_Empty(C - 1, R) then Exch(C - 1, R)
   else if (C < 3) and Is_Empty(C + 1, R) then Exch(C + 1, R)
   else if (R > 0) and Is_Empty(C, R - 1) then Exch(C, R - 1)
   else if (R < 3) and Is_Empty(C, R + 1) then Exch(C, R + 1)
end;

, и играй



1



Мишка Косолапый :)

284 / 254 / 86

Регистрация: 15.02.2012

Сообщений: 1,511

24.05.2012, 12:45

 [ТС]

3

УУ. спс большое)

Добавлено через 7 минут
тока чтот лазарус не понял что такое mypanelclick

Добавлено через 6 минут
а все) работает!



0



0 / 0 / 0

Регистрация: 24.05.2012

Сообщений: 6

24.05.2012, 18:41

4

zuxa-zuxa, а не могли бы вы скинуть мне проект, архивом, буду благодарен)



0



Супер-модератор

Эксперт Pascal/DelphiАвтор FAQ

32464 / 20955 / 8108

Регистрация: 22.10.2011

Сообщений: 36,224

Записей в блоге: 7

24.05.2012, 18:49

5

hawk, я ж написал все, что нужно сделать

Ну вот архив:

Вложения

Тип файла: zip 15.zip (126.0 Кб, 494 просмотров)



1



0 / 0 / 0

Регистрация: 13.05.2015

Сообщений: 2

14.05.2015, 14:18

6

А можно пожалуйста по свойствам панелей по подробнее?



0



Супер-модератор

Эксперт Pascal/DelphiАвтор FAQ

32464 / 20955 / 8108

Регистрация: 22.10.2011

Сообщений: 36,224

Записей в блоге: 7

14.05.2015, 14:22

7

Что именно нужно подробнее? Я же уже и проект присоединил, куда подробнее?



1



0 / 0 / 0

Регистрация: 13.05.2015

Сообщений: 2

14.05.2015, 14:22

8

хорошо



0



0 / 0 / 0

Регистрация: 07.04.2018

Сообщений: 47

25.04.2018, 12:45

9

Извиняюсь за глупый вопрос, не могли бы вы сделать пояснения к коду, а то хотел сам разобраться и ничего не понял

Больший интерес вызывает строка «Result := FindComponent(Format(‘Panel%d’,[4 * R + C + 1])) as TPanel;» я не понимаю что в ней делается



0



Супер-модератор

Эксперт Pascal/DelphiАвтор FAQ

32464 / 20955 / 8108

Регистрация: 22.10.2011

Сообщений: 36,224

Записей в блоге: 7

25.04.2018, 13:08

10

Цитата
Сообщение от Kurasso
Посмотреть сообщение

я не понимаю что в ней делается

В ней находится лежащая на форме панель, представляющая собой ячейку с номером столбца C и номером строки R, и указатель на эту панель возвращается как результат функции.



0



0 / 0 / 0

Регистрация: 07.04.2018

Сообщений: 47

25.04.2018, 13:20

11

Я знаю, это будет нагло с моей стороны, но не могли бы вы сделать комментарии к коду в важных местах

Добавлено через 3 минуты
[4 * R + C + 1]- что это означает ?

if (C > 0) and Is_Empty(C — 1, R) then Exch(C — 1, R)
else if (C < 3) and Is_Empty(C + 1, R) then Exch(C + 1, R) почему и для чего в этих строчках С сравнивается с 0 и 3 , и почему именно с 3 и 0, Почему от с отнимается 1?
Заранее извиняюсь за свою беспросветную глупость, я в программировании очень плох



0



Регистрация через

или E-mail

Получите курс бесплатно

Вы выбрали курс для изучения
«»
Чтобы получить доступ к курсу, зарегистрируйтесь на сайте.

Спасибо за регистрацию

Перейдите на почту и подтвердите Ваш аккаунт,
чтобы получить доступ ко всем
бесплатным урокам и вебинарам на сайте ITVDN.com

Спасибо за регистрацию

Ваш аккаунт успешно подтвержден.
Начать обучение вы можете через Личный кабинет
пользователя или непосредственно на странице курса.

Подтверждение аккаунта

На Ваш номер телефона было отправлено смс с кодом активации аккаунта. Пожалуйста, введите код в поле ввода.

Отправить код еще раз

Изменить номер телефона

ПОДТВЕРДИТЬ ПОЧТУ

На Ваш email было отправлено письмо с кодом активации аккаунта. Пожалуйста, введите код в поле ввода.

Отправить код еще раз

Изменить email

  • Видеоуроки программирования
  • TheMrDen3D
  • [Примеры. Lazarus] Игра Snake2D

[Примеры. Lazarus] Игра Snake2D

Смотреть видеоурок:

С этим видео программисты смотрят следующие ролики:

Поделитесь этим видео с друзьями:

Понравилась статья? Поделить с друзьями:
  • Как написать имя на английском поля
  • Как написать имя мухаммад на арабском языке
  • Как написать имя мая на английском
  • Как написать имя красиво на телефоне
  • Как написать имя иероглифами на японском