Форум программистов, компьютерный форум, киберфорум
QBasic
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Модератор
1245 / 676 / 292
Регистрация: 10.11.2019
Сообщений: 1,406

FreeBasic: простая 2D аркада-шутер

18.09.2024, 12:45. Показов 979. Ответов 0
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Так ли уж сложно написать игру, имея возможности FreeBasic ?
Конечно, библиотеки DirectX и OpenGL дают высокое быстродействие
и потрясающую 3D графику, но они очень уж сложны для новичка.
Особенно, если требуется создавать собственные 3D модели.
Но можно сделать игру, которая не требует 3D, и даже не
использует сложные графические форматы, а только BMP.
Так была сделана "казуальная" игра "Охота на кур" ("Moorhuhn")
начала 2000х годов.
Моя программа на FreeBasic демонстрирует такой подход,
но графики здесь гораздо меньше, чем в Moorhuhn - у меня это просто учебный пример.

Прозрачные спрайты с альфа-каналом.

FreeBasic может самостоятельно (без дополнительных библиотек)
выводить картинки с альфа-каналом. При этом на одну точку картинки
приходится 4 байта: Blue - синий, Green - зелёный, Red - красный, Alpha - прозрачность.
Первые 3 байта задают любой реальный цвет, байт прозрачности задаёт: 0 - полностью
прозрачный, 255 - полностью непрозрачный. Это позволяет добиться красивых
эффектов огня, взрывов, тумана и т д. До сих пор многие графредакторы не
позволяют использовать слой прозрачности (mspaint точно не может).
Слои прозрачности могут сохраняться в форматах изображений BMP, PNG, TGA.
FreeBasic сохраняет такие картинки командой BSAVE, если установлен режим
32 битной цветности SCREEN.

Как сделать спрайт с прозрачностью ?

Главный герой моей игры - смайлик - был сделан рендерингом из бесплатной
3D модели смайлика в программе Poser. Картинка должна иметь размер 128*128.
Преобразование из формата png в bmp сделано программой XnView.
Анимация взрыва была сделана из готовой непрозрачной текстуры с помощью небольшой
программы на FreeBasic.

Звуки и музыка.

Классическим подходом к созданию звуков в (бесплатных и малобюджетных) играх
является использование бесплатной библиотеки bass.dll
Эта библиотека умеет проигрывать файлы форматов wav, mp3 и модульную (трекерную) музыку,
например файлы mod.
В моём примере использована bass.dll версии 2.4 FreeBasic поддерживает
bass.dll "из коробки", правда родные примеры в дистрибутиве FreeBasic довольно
неудачные.

Как сделана анимация в игре ?
(Структуры - это наше всё)


В самых первых играх персонажи довольно тупо двигались все вместе
с одинаковыми скоростями и одинаковым внешним видом (см здесь)

https://ru.wikipedia.org/wiki/Space_Invaders

Но уже игры на ZX-Spectrum поражали возможностью движения врагов-мишеней
и ракет по замысловатым траекториям, с выходом и уходом за границы экрана.
И при этом фоновая картинка игры двигалась ! На современных компьютерах
сложного движения многочисленных спрайтов достаточно легко достигнуть.
Создадим структуру spt такого вида:

QBasic/QuickBASIC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
' Определение типа для работы с спрайтами
TYPE SpriteType
x  AS SINGLE ' координата x
x1 AS SINGLE ' скорость   x
y  AS SINGLE ' координата y
y1 AS SINGLE ' скорость   y
' переменные, используемые для анимации
speed AS SINGLE  ' скорость анимации
speedT AS SINGLE ' таймер анимации
frb AS LONG      ' начальный кадр анимации (и флаг - спрайт активен)
frend AS LONG    ' конечный кадр анимации
fr  AS LONG      ' текущий кадр анимации
anstop AS LONG   ' флаг - однократная анимация
anstopf AS LONG  ' флаг - анимация закончена
END TYPE
' массив спрайтов
DIM SHARED spt(100) AS SpriteType
Теперь напишем такую процедуру:

QBasic/QuickBASIC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
' Функция анимации
SUB anim()
' Эта функция обрабатывает все спрайты (с 1 по 100)
' Это позволяет в дальнейшем анимировать любой спрайт в игре.
FOR i=1 TO 100
' Если поле frb (начальный кадр анимации) > 0, то идет обработка
IF spt(i).frb THEN
'...
'...
'...
' нарисовать спрайт на экране
IF spt(i).frb THEN
PUT (spt(i).x-64,spt(i).y-64),images(spt(i).fr),alpha
END IF
endif
NEXT i
END SUB
Если теперь в основном цикле игры вызвать anim(),
то на экран будут выведены спрайты, причём только те, у которых spt(i).frb<>0

Захотели пристрелить врага - нет ничего проще - достаточно в любом месте программы
присвоить spt(obj).frb=0, где obj - номер спрайта.
Т е движение врагов, их появление, взрывы и т. д. целиком управляются данными
структуры spt()
При этом код движения врагов, код обработки движения мышки (уничтожение врагов)
и код рисования врагов могут находиться в разных процедурах (функциях)

См zip файл с откомпилированной игрой.
Полный текст программы:

QBasic/QuickBASIC
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
'freebasic
REM Created: 18.09.2024
REM (C) Dmitriy Korabelnikov
REM d_korabelnikov@mail.ru
REM Простая игра - спрайтовый 2D шутер
 
#Include "bass.bi"
DEFLNG a-z
' размер экрана
CONST screenw=1024
CONST screenh=768
' центр экрана
CONST screenw2=512
CONST screenh2=384
CONST bordery=64
 
' звуки и музыка
DIM SHARED AS HSAMPLE snd(20)
 
' Определение типа для работы с спрайтами
TYPE SpriteType
x  AS SINGLE ' координата x
x1 AS SINGLE ' скорость   x
y  AS SINGLE ' координата y
y1 AS SINGLE ' скорость   y
' переменные, используемые для анимации
speed AS SINGLE  ' скорость анимации
speedT AS SINGLE ' таймер анимации
frb AS LONG      ' начальный кадр анимации (и флаг - спрайт активен)
frend AS LONG    ' конечный кадр анимации
fr  AS LONG      ' текущий кадр анимации
anstop AS LONG   ' флаг - однократная анимация
anstopf AS LONG  ' флаг - анимация закончена
END TYPE
 
' массив спрайтов
DIM SHARED spt(100) AS SpriteType
 
DIM SHARED mousex AS LONG,mousey AS LONG,mbutton AS LONG,kbdelay AS LONG
DIM SHARED crossimg AS ulong ptr,bgimg AS ulong ptr
DIM SHARED images(100) AS ulong ptr
DIM SHARED maxsmiles AS LONG,hits AS LONG,missed AS LONG
 
FUNCTION irnd(n AS LONG) AS LONG
irnd=INT(n*RND)
END FUNCTION
 
FUNCTION srnd(n AS SINGLE) AS SINGLE
srnd=n*RND
END FUNCTION
 
' Is file n$ exist ?
FUNCTION exist(n$) AS LONG
re=OPEN(n$,FOR INPUT,AS #9)
CLOSE #9
IF re=0 THEN exist=-1 ELSE exist=0
END FUNCTION
 
SUB bassbegin
r=BASS_GetVersion()
' Initialize BASS using the default device at 44.1 KHz.
r=BASS_Init(-1, 44100, 0, 0, 0)
END SUB
 
SUB bassend
r=BASS_Free()
END SUB
 
SUB errnofile(n$)
screenset 0,0
CLS
bassend
PRINT n$;" - file not found";
SLEEP
END
END SUB
 
FUNCTION LoadSound(n$) AS DWORD
DIM r AS DWORD
IF NOT exist(n$) THEN errnofile(n$)
r = BASS_MusicLoad(0, StrPtr(n$), 0, 0, BASS_SAMPLE_LOOP, 0)
IF r = 0 THEN r = BASS_StreamCreateFile(BASSFALSE,StrPtr(n$), 0, 0, 0)
LoadSound=r
END FUNCTION
 
SUB PlaySound(n AS LONG)
BASS_ChannelPlay(snd(n), 1)
END SUB
 
' Движение врагов
SUB motion()
' В цикле по номерам спрайтов
FOR i=1 TO 100
IF spt(i).frb THEN
' Если спрайт уходит за левую границу экрана, двигать его вправо
IF spt(i).x<0 THEN spt(i).x1=ABS(spt(i).x1)
' Если спрайт уходит за правую границу экрана, двигать его влево
IF spt(i).x>screenw THEN spt(i).x1=-ABS(spt(i).x1)
' Изменить координату X
spt(i).x=spt(i).x+spt(i).x1
END IF
NEXT i
END SUB
 
' Функция анимации
SUB anim()
' Эта функция обрабатывает все спрайты (с 1 по 100)
' Это позволяет в дальнейшем анимировать любой спрайт в игре.
FOR i=1 TO 100
' Если поле frb (начальный кадр анимации) > 0, то идет обработка
IF spt(i).frb THEN
fr=spt(i).fr:frb=spt(i).frb:frend=spt(i).frend
' Если текущий кадр вне диапазона, текущий кадр = начальный
IF fr<frb OR fr>frend THEN fr=frb
' Следующий замысловатый код плавно меняет скорость анимации
' в зависимости от значения .speed
' Если .speed=100.0, то анимация будет меняться в каждом кадре
' (учитывая, что мы задали 50 кадров в секунду)
' Если .speed=50, анимация будет меняться в каждом втором кадре и т д
' При таком способе при плавном изменении .speed анимация меняется
' плавно, а не скачками.
spt(i).speedT=spt(i).speedT-spt(i).speed
IF spt(i).speedT<=0 THEN
spt(i).speedT=spt(i).speedT+100.0
fr=fr+1
' Есть возможность делать анимацию однократной (не циклической)
' установкой флага .anstop
IF fr>=frend THEN
  IF spt(i).anstop THEN
    spt(i).frb=0:spt(i).anstopf=1
  ELSE
    fr=frb
  endif
endif
spt(i).fr=fr
endif
' нарисовать спрайт на экране
IF spt(i).frb THEN
PUT (spt(i).x-64,spt(i).y-64),images(spt(i).fr),alpha
END IF
endif
 
NEXT i
END SUB
 
' Проверка попаданий
SUB testcollision(mx,my)
' line (mx-32,my-32)-step(63,63),rgb(255,0,0),"bf":sleep 500
found=0
' Для всех спрайтов врагов
FOR i=100 TO 1 STEP -1
IF spt(i).frb>0 AND spt(i).anstop=0 THEN
' Если растояние от прицела до центра врага не больше 32 точек
IF ABS(spt(i).x-mx) + ABS(spt(i).y-my)<32 THEN
found=1
' Остановить движение врага (скорость=0)
spt(i).x1=0
' Заменить анимацию "мордочки" на анимацию взрыва
spt(i).frb=16:spt(i).frend=31:spt(i).anstop=1
' Включить звук взрыва (12) и один из 10 воплей
PlaySound 1+(i MOD 10)
PlaySound 12
' Изменить счёт игры
maxsmiles=maxsmiles-1:hits=hits+1
endif
endif
IF found THEN EXIT FOR
NEXT i
' Если не попали, включить звук "свистящей мимо" пули
IF found=0 THEN PlaySound 13:missed=missed+1
END SUB
 
' Управлять мышью
SUB mousecontrol()
getmouse mousex,mousey,,mbutton
' Увеличим чувствительность мыши в 2 раза
' (где screenw2 и screenh2 - половина высоты и ширины экрана)
mx=screenw2+2*(mousex-screenw2)
my=screenh2+2*(mousey-screenh2)
IF mx<0 THEN mx=0
IF my<0 THEN my=0
IF mx>screenw THEN mx=screenw
IF my>screenh THEN my=screenh
mousex=mx
mousey=my
' kbdelay используется для задержки .5 сек при нажатии на кнопку мышки
IF kbdelay>0 THEN kbdelay=kbdelay-1
IF kbdelay=0 THEN
' Если нажата левая кнопка мыши, проверить попадание
IF (mbutton AND 1)<>0 THEN
kbdelay=25:testcollision(mx,my)
endif
endif
END SUB
 
' Создать нового врага, присвоив случайные значения координат
SUB generate(obj)
' если спрайт с номером obj активен, то выйти (ничего не делать)
IF spt(obj).frb THEN EXIT SUB
spt(obj)=spt(0)
' Начальные координаты и анимация
spt(obj).frb=1:spt(obj).frend=15
spt(obj).fr=1+irnd(14)
spt(obj).x=srnd(screenw)
spt(obj).x1=3+srnd(4):IF rnd>.5 THEN spt(obj).x1=-spt(obj).x1
spt(obj).y=bordery+irnd(screenh-2*bordery)
spt(obj).speed=30
' увеличить счётчик спрайтов
maxsmiles=maxsmiles+1
END SUB
 
' преобразование числа в текст
' используется при загрузке файлов и выводе счёта
FUNCTION tx$(v,n)
    tx$=RIGHT$(STR$(1000000000+v),n)
END FUNCTION
 
' финальное сообщение игры
SUB finalwords()
screenset 0,0:CLS
WHILE INKEY$=CHR$(27):SLEEP 20:WEND
t$="THANK YOU FOR PLAYING!"
le=LEN(t$)
x=64-INT(le/2)
y=24
FOR n=1 TO le
m$=MID$(t$,n,1)
IF m$<>" " THEN
FOR i=47 TO y STEP -1
  LOCATE i+1,x+n:PRINT " ";
  LOCATE i,x+n:PRINT m$;
  IF INKEY$=CHR$(27) THEN EXIT SUB
  SLEEP 20
NEXT i
END IF
NEXT n
FOR i=1 TO 200
  IF INKEY$=CHR$(27) THEN EXIT SUB
  SLEEP 20
NEXT i
END SUB
 
' основная программа
screenres screenw,screenh,32,2,5
WIDTH screenw/8,screenh/16
' загрузка картинок
p$=exepath+"\gamedata"
ind=1
FOR i=1 TO 15
images(i)=imagecreate(128,128)
n$=p$+"\emot\emoti"+tx$(ind,2)+".bmp"
IF NOT exist(n$) THEN errnofile(n$)
BLOAD n$,images(i)
ind=ind+2
NEXT i
 
ind=1
FOR i=16 TO 31
images(i)=imagecreate(128,128)
n$=p$+"\explod\explod"+tx$(ind,2)+".bmp"
IF NOT exist(n$) THEN errnofile(n$)
BLOAD n$,images(i)
ind=ind+1
NEXT i
 
crossimg=imagecreate(64,64)
n$=p$+"\cross.bmp"
IF NOT exist(n$) THEN errnofile(n$)
BLOAD n$,crossimg
bgimg=imagecreate(screenw,screenh)
n$=p$+"\palm1024.bmp"
IF NOT exist(n$) THEN errnofile(n$)
BLOAD n$,bgimg
' поставить курсор мышки в центр и сделать его невидимым
setmouse screenw2,screenh2,0
' инит звуковую библиотеку
bassbegin
' загрузить музыку
snd(20)=LoadSound(p$+"\skogen01.mod")
' Загрузить звуки
FOR i=1 TO 10
snd(i)=LoadSound(p$+"\sound\sn"+tx$(i,2)+".wav")
NEXT i
snd(12)=LoadSound(p$+"\sound\explosion.wav")
snd(13)=LoadSound(p$+"\sound\rippler.wav")
tick=0
apage=0
FOR i=1 TO 5
    IF maxsmiles<20 THEN generate(1+irnd(99))
NEXT i
' играть музыку
PlaySound 20
' цикл игры
DO
    screenset apage,1-apage
    apage=1-apage
    PUT (0,0),bgimg,PSET
'   status()    
    LOCATE 2,2:PRINT "SMILES ";tx$(maxsmiles,2);" HITS ";tx$(hits,6);" MISSED ";tx$(missed,6);
'   выход из игры по ESC
    IF INKEY$()=CHR$(27) THEN bassend:finalwords:END
' Генерировать нового врага 1 раз в 96 циклов
    tick=tick+1
    IF tick=96 THEN
        tick=0
        IF maxsmiles<20 THEN generate(1+irnd(99))
    endif
' двигать спрайты
    motion
' движение мышки и обработка стрельбы
    mousecontrol
' анимация и вывод спрайтов
    anim
' рисовать курсор мышки (прицел)
    PUT (mousex-32,mousey-32),crossimg,alpha
' задержка 20 миллисекунд (50 кадров в секунду)
    SLEEP 20
LOOP
END
Миниатюры
FreeBasic: простая 2D аркада-шутер  
Вложения
Тип файла: zip fbshoot.zip (1.92 Мб, 42 просмотров)
3
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
18.09.2024, 12:45
Ответы с готовыми решениями:

Аркада на Python
Добрый день! Пишу свою аркаду на python 3 (tkinter), но есть проблема: def main(event): if event.keysym in &quot;d&quot;: ...

[2D] Colorful - аркада / тайм-киллер
От меня: Добрый день! Решил сделать для портфолио один простенький тайм-киллер с минимальным графическим оформлением. Хотелось бы...

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

0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
18.09.2024, 12:45
Помогаю со студенческими работами здесь

Оцените игру-шутер
uses graphabc,events,Timers; type massiv=array of integer; var x1,y1,x2,y2:massiv; x:array of integer; y:array of integer; ...

Шутер, не получаются руки
Я делаю шутер. FPS готов. Руки ни как не получаются. Помогите, пожалуйста сделать руки! Персонаж из...

Шутер F.E.A.R. 3 запоздает с выходом
Шутер от первого лица F.E.A.R. 3 задержится с выпуском, с сожалением сообщает издательство Warner Bros. Interactive. Игра должна была выйти...

Классный шутер онлайн
Посоветуйте сабж, который пойдет из под винды икспи. Больше сабжи для икспи не делают? Также желательно, чтобы был нетребователен - на...

Смерть NPC (2D шутер)
Помогите разобраться с таким вопросом. Есть NPC (солдат), у него прописаны скелетные анимации (спокойствие, ходьба, стрельба стоя, стрельба...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
1
Ответ Создать тему
Новые блоги и статьи
Символьное дифференцирование
igorrr37 13.02.2026
/ * Логарифм записывается как: (x-2)log(x^2+2) - означает логарифм (x^2+2) по основанию (x-2). Унарный минус обозначается как ! */ #include <iostream> #include <stack> #include <cctype>. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru