Javascript Roguelike/Rpg (30 Строк Кода)

После серии постов о реализации простых игрушек на JavaScript в 30 строк, я решил попробовать себя в этом «соревновании».

Посидев вечер, мне удалось создать «полноценный» Roguelike/RPG (я не очень разбираюсь в жанрах, но кое-что в этом направлении получилось).

Параллельно я изучал JavaScript (раньше никогда на нем не писал, как-то баловался C++).



JavaScript Roguelike/RPG (30 строк кода)

Особенности:

  • Случайно сгенерированный мир
  • Прокачка вашего персонажа
  • 3 типа врагов и финальный босс
  • Инвентарь с бутылочками с зельями и магазином для их пополнения


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

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

После сражений с монстрами герой получает золото и жизненный опыт. Золото можно потратить на лечение и покупку лечебных зелий в магазинах по пути.

Жизненный опыт повышает уровень героя, что увеличивает его атаку и защиту.

Цель игры — полностью подготовиться к битве с драконом, а затем победить его и освободить принцессу.

Ссылка к скрипка .



Код
За основу я взял код из эта почта , а затем «допилил» его до нужного мне состояния.

Исходный код (см.

скрипка ): Источник

  
   

(function(elid, wi, he, exp, pot, gld, hp, lvl, cur_e, e_sz){ var hit = function(){ evs[cur_e][8]-=lvl*4+6; if(evs[cur_e][8]<=0) { alert("Monster defeated and you got "+evs[cur_e][10]+"EXP and $"+evs[cur_e][11]); exp+=evs[cur_e][10];gld+=evs[cur_e][11]; while(exp>=lvl*10){exp-=lvl*10;lvl++;alert("Level Up!")} cur_e++; if(cur_e==e_sz) alert("Victory!") } else { hp-=Math.max(0,evs[cur_e][9]-lvl*2-1); if(hp<=0) alert("Game Over!") } } var use = function(){ if (pot>0){pot--;hp+=10;if(hp>100)hp=100} } var nxt = function(){ cur_e++ }, battle = ["Attack","Use Potion +10HP","Skip Battle",hit,use,nxt], canvas=document.querySelector(elid), ctx=canvas.getContext("2d"), evs=[], e_tp=[ ["Shop", "Wizard provides his services", "Buy Potion $20", "Full Heal $100", "Leave", function(){ if(gld>=20){gld-=20;pot++} }, function(){ if(gld>=100){gld-=100;hp=100} }, nxt ], ["Skeleton", "A terrible skeleton on your way"].

concat(battle,70,15,25,100), ["Goblin", "Green goblin wants to get your money"].

concat(battle,50,10,15,70), ["Slime", "What the strange jelly monster?"].

concat(battle,20,6,7,30), ["Dragon", "Omg! It is evil Dragon!","Attack","Use Potion +10HP","-",hit,use,,300,25,100,1000 ] ], q=e_tp.length-1; canvas.width=wi; canvas.height=he; for (var i=0;i<e_sz-1;i++) evs.push( e_tp[Math.floor(Math.random()*q)].

slice(0) ); evs.push( e_tp[q].

slice(0) ); var game = setInterval(function(){ ctx.clearRect(0,0,wi,he); ctx.fillText("NanoRPG in 30 lines of JavaScript by ripatti",10,15); ctx.fillText("LVL "+lvl+" HP "+hp+"/100 EXP "+exp+"/"+lvl*10+" ATK "+(lvl*4+6)+ " DEF "+(lvl*2+1)+" Gold $"+gld+" Potions "+pot,10,30); for (var i=0;i<e_sz;i++) ctx.fillText((i==e_sz-1||i<=cur_e)Эevs[i][0]:"??",i*50+15,70); ctx.fillText("@",cur_e*50+25,60); ctx.fillText(evs[cur_e][1],20,100); if (evs[cur_e].

length>8) ctx.fillText("Enemy HP "+evs[cur_e][8],250,100); for (var i=0;i<3;i++) { ctx.strokeRect(i*120+5,120,110,20); ctx.fillText(evs[cur_e][i+2],i*120+10,133); } }, 100); document.addEventListener('click', function(e){ for (var i=0;i<3;i++) if (i*120+5<=e.pageX && e.pageX<i*120+115 && 120<=e.pageY && e.pageY<140) if (hp>0) evs[cur_e][i+5]() }, false); })("#canvas",365,150,0,3,100,100,1,0,7);

Чуть более читабельная версия на 50 строк (см.

скрипка ): Источник

(function(elid, wi, he, exp, pot, gld, hp, lvl, cur_e, e_sz){ var hit = function(){ evs[cur_e][8]-=lvl*4+6; if (evs[cur_e][8]<=0) { alert("Monster defeated and you got "+evs[cur_e][10]+"EXP and $"+evs[cur_e][11]); exp+=evs[cur_e][10]; gld+=evs[cur_e][11]; while (exp>=lvl*10) { exp-=lvl*10; lvl++; alert("Level Up!") } cur_e++; if (cur_e==e_sz) alert("Victory!") } else { hp-=Math.max(0,evs[cur_e][9]-lvl*2-1); if(hp<=0) alert("Game Over!") } } var use = function(){ if (pot>0){pot--;hp+=10;if(hp>100)hp=100} } var nxt = function(){ cur_e++ } var battle = ["Attack", "Use Potion +10HP", "Skip Battle", hit, use, nxt]; var canvas=document.querySelector(elid), ctx=canvas.getContext("2d"); canvas.width=wi; canvas.height=he; var evs=[], e_tp=[ ["Shop", "Wizard provides his services", "Buy Potion $20", "Full Heal $100", "Leave", function(){ if(gld>=20){gld-=20;pot++} }, function(){ if(gld>=100){gld-=100;hp=100} }, nxt ], ["Skeleton", "A terrible skeleton on your way"].

concat(battle,70,15,25,100), ["Goblin", "Green goblin wants to get your money"].

concat(battle,50,10,15,70), ["Slime", "What the strange jelly monster?"].

concat(battle,20,6,7,30), ["Dragon", "Omg! It is evil Dragon!","Attack","Use Potion +10HP","-",hit,use,,300,25,100,1000 ] ]; var q=e_tp.length-1; for (var i=0;i<e_sz-1;i++) evs.push( e_tp[Math.floor(Math.random()*q)].

slice(0) ); evs.push( e_tp[q].

slice(0) ); var game = setInterval(function(){ ctx.clearRect(0,0,wi,he); ctx.fillText("NanoRPG in 30 lines of JavaScript by ripatti",10,15); ctx.fillText("LVL "+lvl+" HP "+hp+"/100 EXP "+exp+"/"+lvl*10+" ATK "+(lvl*4+6)+ " DEF "+(lvl*2+1)+" Gold $"+gld+" Potions "+pot,10,30); for (var i=0;i<e_sz;i++) ctx.fillText((i==e_sz-1||i<=cur_e)Эevs[i][0]:"??",i*50+15,70); ctx.fillText("@",cur_e*50+25,60); ctx.fillText(evs[cur_e][1],20,100); if (evs[cur_e].

length>8) ctx.fillText("Enemy HP "+evs[cur_e][8],250,100); for (var i=0;i<3;i++) { ctx.strokeRect(i*120+5,120,110,20); ctx.fillText(evs[cur_e][i+2],i*120+10,133); } }, 100); document.addEventListener('click', function(e){ if (hp>0) for (var i=0;i<3;i++) if (i*120+5<=e.pageX && e.pageX<i*120+115 && 120<=e.pageY && e.pageY<140) evs[cur_e][i+5]() }, false); })("#canvas",365,150,0,3,100,100,1,0,7);

Код для html и css я не учел, но если кому интересно: html — 1 строка кода, css — 4.

Заключение
Спасибо Агегорин позади раса , DJComandos позади змея И линолеум позади арканоид .

Было интересно почитать исходный код и написать на его основе что-то свое.



UPD Рогалик/РПГ в коде 4Кб на JavaScript
Товарищ Шведовка предложил сделать циклическую игру большей сложности, что я и сделал.

В 30 строк он вообще не умещался, поэтому я взял еще одно ограничение: код должен быть не более 4 килобайт (это согласуется с замечанием лолмаус , и мне лично так больше нравится).

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

А именно:

  • Арена, где можно обменять деньги на опыт во время тренировки
  • Кузница, где можно улучшить свой меч и доспехи
  • +2 типа врагов - всего теперь 5 типов
Небольшие изменения в генерации мира:
  • Некоторые монстры и здания появляются только в том случае, если вы пройдете игру несколько раз.

  • Одна из двух локаций перед замком дракона определенно будет магазином.

И много мелких изменений в плане баланса всего.

И да.

теперь принцессу действительно можно спасти.

Ссылка на эту версию игры по адресу скрипка .

Получилось довольно хардкорно.

Хорошо код , Конечно.

Форматирование не очень четкое — я удалил некоторые пробелы, чтобы сохранить длину в 4000 символов.

В принципе, код можно еще сильнее сжать, чтобы втиснуть еще одно событие, например (была идея сделать что-то вроде казино).

Но мне лень это делать.

На этом я считаю работу над игрой завершенной.

Теги: #JavaScript #игра #canvas #30 линий #rpg #roguelike #Ненормальное программирование #JavaScript

Вместе с данным постом часто просматривают: