Non-reflective: Победил артефакты, но снова стали актуальны тормоза:)

Hoshi Saga Ringohime

Grand Mystic Quest of Discovery

Pill Cannon

Гаминатор 27. оТкРыТиЕ.

Избранное пользователя

В привычном значении слова, у этой игры наверное нет шейдеров. Здесь весь код постпроцессинга картинки прямо в самом коде игры на Си, как и вся игра.

Сама игрушка изначально черно-белая, все ассеты тоже черно белые. Если отрендерить без кода постпроцессинга, то получится вот так:

GZaQJnW

Дальше каждый пиксель затемняется в зависимости от его глубины в кадре:

Ic8tvX3

И дальше главная функция постпроцессинга опять же проходит про каждому пикселю и заменяет его на один из 8 цветов палитры, попутно применяя кое-какой дизеринг:

GYL0dI4

unsigned char pal[8][3] = {
    {  1,  63,  79  },
    { 22,  70,  96  },
    { 74,  78,  104 },
    { 131, 105, 122 },
    { 198, 129, 89  },
    { 235, 170, 94  },
    { 245, 212, 163 },
    { 255, 236, 214 }
};

void set_with_pal(unsigned int x, unsigned int y, int pal_idx) {
    set(x, y, pal[pal_idx][0], pal[pal_idx][1], pal[pal_idx][2]);
}

void postproc() {
    unsigned char r, g, b;
    for (unsigned int x = 0; x < WIDTH; x ++)
    for (unsigned int y = 0; y < HEIGHT; y ++) {
        get(x, y, &r, &g, &b);

        r /= 8;
        r -= 3;
        if (r > 32) {
            r = 0;
        }

        if (r % 4 == 0) {
            set_with_pal(x, y, r / 4);
        } else if (r % 2 == 0) {
            int one = (r - 2) / 4;
            int two = (r - 2) / 4 + 1;

            if ((y + x) % 2) {
                set_with_pal(x, y, one);
            } else {
                set_with_pal(x, y, two);
            }
        } else {
            int one = (r % 4 == 1) ? (r - 1) / 4 + 1 : (r - 3) / 4;
            int two = (r % 4 == 1) ? (r - 1) / 4 : (r - 3) / 4 + 1;

            if ((y % 2) == (r % 4 == 1) && x % 2) {
                set_with_pal(x, y, one);
            } else {
                set_with_pal(x, y, two);
            }
        }
    }
}

get(x, y, r, g, b) и set(x, y, r, b, g) - это соответственно функции чтобы достать и проставить пиксель (x, y)

Если код интересует, то в моём случае это выглядит примерно так:

MAP_init

globalvar MAP_grid, MAP_walls, MAP_visit, MAP_x, MAP_y, MAP_direction, MAP_surface, MAP_targets, MAP_target_count, MAP_rooms;

MAP_grid = ds_grid_create(5,5);
ds_grid_clear(MAP_grid,room_proto);
MAP_visit = ds_grid_create(5,5);
ds_grid_clear(MAP_visit, 0);
MAP_walls = ds_map_create();

MAP_x=0;
MAP_y=0;
MAP_direction=0;
MAP_surface=-1;
MAP_targets=ds_map_create();
MAP_target_count=0;

MAP_rooms=ds_list_create();
ds_list_add(MAP_rooms,room_0,room_1,room_2,room_3,room_4,room_5,room_6,room_7,room_8,room_9);

Map_generate

var _w = max(argument[0],2), _h=max(argument[0],2);
ds_grid_resize(MAP_grid,_w,_h);
ds_map_clear(MAP_walls);

var l=ds_list_create(), g = ds_grid_create(_w,_h);
var len = _w*_h;
ds_grid_clear(MAP_grid,room_4);
ds_grid_clear(MAP_visit, 0);

// l - это список комнат, которые я потом перемешаю
// сперва точка старта
ds_list_add(l,room_start);
// Потом комнаты-цели, и вообще любые важные но одноразовые для уровня комнаты(магазы, алтари и т.д.)
// сколько нужно
for(var _i=0;_i<3;_i++) {
	ds_list_add(l,choose(room_target_1,room_target_2));
}

// А это массив со всеми видами комнат, я его буду перемешивать
// и накидывать из него комнат, это нужно, чтобы комнаты как можно меньше раз повторялись за одну карту.
// В идеале его размер должен быть в несколько раз больше чем количество ячеек карты
ds_list_shuffle(MAP_rooms);
var _rindx = 0;

while(ds_list_size(l)<len) {
	ds_list_add(l,MAP_rooms[| _rindx]);
	_rindx++;
	if _rindx>ds_list_size(MAP_rooms)-1 then {
		ds_list_shuffle(MAP_rooms);
		_rindx=0;
	}
}

MAP_target_count=3;
ds_map_clear(MAP_targets);

// А теперь перемешиваем их расположение
ds_list_shuffle(l);

//По порядку забиваем в массив, отмечаем точку старта игрока
var _mx = 0, _my=0;
for(var _i=0;_i<ds_list_size(l);_i++) {
	var _r = l[| _i];
	if _r==room_start then {
		MAP_x = _mx;
		MAP_y = _my;
	}
	MAP_grid[# _mx, _my]=_r;
	_mx++;
	if _mx>=ds_grid_width(MAP_grid) then {
		_mx=0;
		_my++;
	}
}

ds_list_clear(l);
// Генерим стенки, вот этот ут - как раз "дырявость карты"
len = floor(len*(0.5+random(0.5)));
randomize();
for(var i=0; i<len; i++) {
	// Выбираем случайную комнату
	var _x1=irandom(_w-1),_y1=irandom(_h-1);
	var val1 = string(_x1)+"|"+string(_y1);
	
	//Здесь будем выбирать случайное направление с учётом того что там может быть граница
	if _x1>0 then ds_list_add(l,string(_x1-1)+"|"+string(_y1));
	if _x1<_w-1 then ds_list_add(l,string(_x1+1)+"|"+string(_y1));
	if _y1>0 then ds_list_add(l,string(_x1)+"|"+string(_y1-1));
	if _y1<_h-1 then ds_list_add(l,string(_x1)+"|"+string(_y1+1));
	
	ds_list_shuffle(l);
	var val2 = l[| 0];
	ds_list_clear(l);
	
	// А это если случайно там уже есть стена = фейл-попытка
	if ds_map_exists(MAP_walls,val1+"="+val2) || ds_map_exists(MAP_walls,val2+"="+val1) then continue;
	
	// Пытаемся поставить стену
	ds_map_add(MAP_walls,val1+"="+val2,true);
	ds_map_add(MAP_walls,val2+"="+val1,true);
	
	// Сбрасываем карту посещений
	ds_grid_clear(g,0);
	// Проверяем проходимость
	mapWalk(0,0,g);
	var _min = ds_grid_get_min(g,0,0,_w,_h);
	// Если хотя бы одна комната не посещена, значть карта непроходима - убираем стенку
	if _min==0 then {
		ds_map_delete(MAP_walls,val1+"="+val2);
		ds_map_delete(MAP_walls,val2+"="+val1);
	}
}

ds_list_destroy(l);
ds_grid_destroy(g);

MAP_visit[# MAP_x, MAP_y] = 1;

Банальный обход сетки mapWalk

/// @description walk around the grid
/// @param x
/// @param y
/// @param visits
var _x = argument[0], _y=argument[1];

ds_grid_set(argument[2],_x,_y,1);

var _sl = string(_x)+"|"+string(_y)+"="+string(_x-1)+"|"+string(_y);
var _sr = string(_x)+"|"+string(_y)+"="+string(_x+1)+"|"+string(_y);
var _su = string(_x)+"|"+string(_y)+"="+string(_x)+"|"+string(_y-1);
var _sd = string(_x)+"|"+string(_y)+"="+string(_x)+"|"+string(_y+1);

if _x<ds_grid_width(MAP_grid)-1 && !ds_map_exists(MAP_walls,_sr)  && ds_grid_get(argument[2],_x+1,_y)==0 
	mapWalk(_x+1,_y,argument[2]);
if _x>0 && !ds_map_exists(MAP_walls,_sl) && ds_grid_get(argument[2],_x-1,_y)==0 
	mapWalk(_x-1,_y,argument[2]);
	
if _y<ds_grid_height(MAP_grid)-1 && !ds_map_exists(MAP_walls,_sd) && ds_grid_get(argument[2],_x,_y+1)==0 
	mapWalk(_x,_y+1,argument[2]);
if _y>0 && !ds_map_exists(MAP_walls,_su) && ds_grid_get(argument[2],_x,_y-1)==0 
	mapWalk(_x,_y-1,argument[2]);
return true;

Я бы лучше вот что предложил.

Идёшь на https://www.steamgifts.com, создаёшь раздачу своей игры на 50 ключей сроком на 4 дня.

Почему 50 - потому что начиная с 50 раздача попадает в featured блок наверху страницы, куда будет случайно выдаваться на протяжении всего 4 дней. Почему 4 - потому что только последние 4 дня раздачи так происходит, это их правило.

Зачем? По количеству желающих получить твою игру, хоть и бесплатно, можно судить, игра действительно плохая и никому не нужная, или про неё просто не знает достаточно людей. Я это называю "индекс SteamGifts". Во всяком случае, у нас, у этой игры и у этой игры желающих более 10,000. А вот у какой-то казуалки, от которой сразу раздавали 300,000 ключей, желающих было всего 500, зато такое количество ключей позволяло этой казуалке выскакивать в блоке в 99% случаев, потому что чем больше ключей раздаётся - тем чаще показывается игра.

А всё-таки зачем? Затем что так люди узнают про твою игру самым дешёвым способом из возможных. Те, кому игра сильно понравилась, купят её, даже не участвуя в раздаче. Те, кому она просто понравилась, поучаствуют в раздаче и внесут в вишлист. А вишлист - значит этим людям будут показываться скидки на неё, целой капсулой. Ну и может там ещё что-то, смотря что Valve придумает или поменяет, а то они постоянно всё перелопачивают. Само собой, друзья увидят эту игру в их списке и могут покупать гифты. Ну это конечно долгая история, в основном это приходится на дни рождения и Новые Годы. Долгосрочная перспектива, в общем.

Больших надежд на это возлагать не стоит. Но попробовать - вполне.

Ещё могу предложить поменяться ключами. Мы вам 50 Замков Невозврата 2, вы нам 50 Ghost Croquet'ов. Строго для раздачи на том же СтимГифтс. В описании напишете - ключи взяты у разработчиков, а ещё зацените нашу игрушку вот здесь, и ссылку на неё. Специально пишу сюда, чтоб все видели, какой был уговор, если что.

Люди, подхваченные на раздачах, в целом относятся намного более вежливо и адекватно к полученному, чем типичные зажратые покупатели-геймеры. Да, там есть и халявщики, набивающие карточки, куда же без них. Есть просто школьники. Есть боты. Но где-то там, среди всей этой массы, есть и настоящие игроки. Я так нашёл несколько весьма интересных лично мне людей из эпохи ZX Спектрума и 90-х. Не забывайте проверять комментарии. Хотя, я думаю, у вас-то это проблем не вызовет.

Мы свою игру раздаём тупо каждые 4 дня новые 50 ключей. На продажи не влияет - каждый раз приходят новые тысячи желающих. А вот на вишлисты влияет. Там же я и переводчиков понабирал, половину как минимум. Дискуссию на Стиме мало кто видит, а тут и не купившие резко превращаются в обладателей и сарафанное радио для своих друзей.

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

Не, срок большой. Да и вот с авторскими правами не очень хорошо. Хотелось бы продолжить игру после конкурса разрабатывать. Буду значит Гаминатора ждать, что поделать... Но спасибо за информацию

у меня длинный список вкладок сайтов которые я просматриваю, чтобы выбрать картинку. )
Хотя в последние время, появился определенный лиддер по ним.


1. http://hello-zombie.tumblr.com/
2. http://rampagedreality.com/
3. http://fashionablygeek.com/
4. http://www.geek-art.net/
5. http://theawkwardgamer.tumblr.com/
6. http://magicalgametime.com/ - эту ссылку, когда-то Нурпхатор просил.
7. http://tepidsloth.com/
8. http://www.ltdartgallery.com/products