Дневник разработки - "Сан Саныч и белочка против зомби" (Come-from-Beyond)

В ожидании начала конкурса я много раз прокручивал в голове механику игры и понял, что если игрок управляет действиями Сан Саныча через белочку, то это неудобно. Можно передвигать белочку, сказав Сан Санычу "иди за мной", но там, где нужна точная координация действий, подобный подход превратит управление в мучение. Поэтому я немного изменил концепцию игры. Белочка будет выступать в роли т.н. "давателя квестов" (quest giver) и советчика, а игрок будет управлять Сан Санычем. Такой прием также позволит увеличить степень сопереживания главному герою и позволит внести некоторые неожиданные повороты в сюжет.

Первый этап, который я наметил - разработать интерфейс и определиться какие технологии HTML 5 будут использоваться.

Последняя правка: пн, 15/11/2010 - 10:46
Submitted by Come-from-Beyond on

Комментарии

Сделал основу игры. Получилось похоже на одну из игр, которую видел на ZX Spectrum 20 лет назад. Залил html-файл в публичную папку, но как запускать оттуда через браузер не разобрался. Поэтому даю ссылку на другое место: apocatastasis.ru/sansan.html.

Работает в браузере, поддерживающем HTML 5.

Как играть. Красные квадратики - зомби. Зеленый - Сан Саныч. Белые - ящики с товарами. Передвижение осуществляется кликаньем на клетку слева-справа-сверху-снизу от Сан Саныча. Если там пусто, то Сан Саныч просто делает туда шаг. Если там ящик, а за ящиком пусто, то ящик сдвигается. Если за ящиком зомби, то зомби дохнет. Если за ящиком еще один ящик или край игрового поля, то ящик, который толкает Сан Саныч, разрушается. Что-бы выиграть, надо задавить ящиками всех зомби, шатающихся по игровому полю. Внимание! Если зомби подойдет вплотную к Сан Санычу, то последний тоже станет зомби. Дальше по идее должен идти второй уровень, но в конкурс он не входит.

Игра настраиваемая. Для этого надо открыть исходный текст HTML-файла и найти в начале строки:

var BlockSize = 16, ColumnsQty = 30, RowsQty = 20;

задает размер квадратиков, ширину и высоту поля соответственно.

var SS_X = 15, SS_Y = 10, SafetyRadius = 10;

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

var EmptySpacesWeight = 60, ZombiesWeight = 10, BoxesWeight = 30;

весовые коэффициенты для пустого пространства, зомби и ящиков. В приведенном примере соотношение 60:10:30.

PS: Если не удалось открыть код в браузере, то можно скопировать следующий текст в файл с расширением .html и запустить двойным щелчком.<!DOCTYPE html> Сан Саныч и белочка против зомби body {background-color: ; margin: 0px; padding: 0px;} canvas {position: absolute;}

var BlockSize = 16, ColumnsQty = 30, RowsQty = 20;

var SS_X = 15, SS_Y = 10, SafetyRadius = 10;

var EmptySpacesWeight = 60, ZombiesWeight = 10, BoxesWeight = 30;

var Field = [];

function Init() { for (var i = 0; i < ColumnsQty; i++) for (var j = 0; j < RowsQty; j++) { var Type = Math.random() * (EmptySpacesWeight + ZombiesWeight + BoxesWeight); if (Type < EmptySpacesWeight) Field[j * ColumnsQty + i] = 0; else { if (Type < EmptySpacesWeight + ZombiesWeight) { if ((i - SS_X) * (i - SS_X) + (j - SS_Y) * (j - SS_Y) > SafetyRadius * SafetyRadius) Field[j * ColumnsQty + i] = 1; else Field[j * ColumnsQty + i] = 2; } else Field[j * ColumnsQty + i] = 2; } } Field[SS_Y * ColumnsQty + SS_X] = 0;

}

function Paint() { var Canvas = document.getElementById("Canvas"); Canvas.width = ColumnsQty * BlockSize; Canvas.height = RowsQty * BlockSize; Canvas.style.left = ((innerWidth - Canvas.width) >> 1) + "px"; Canvas.style.top = ((innerHeight - Canvas.height) >> 1) + "px"; var Context = Canvas.getContext("2d"); for (var i = 0; i < ColumnsQty; i++) for (var j = 0; j < RowsQty; j++) { switch (Field[j * ColumnsQty + i]) { case 0: Context.fillStyle = "";

break;

case 1: Context.fillStyle = "";

break;

default: Context.fillStyle = ""; } Context.fillRect(i * BlockSize, j * BlockSize, BlockSize, BlockSize); } Context.fillStyle = ""; Context.fillRect(SS_X * BlockSize, SS_Y * BlockSize, BlockSize, BlockSize);

}

function CheckClick(x, y) { var Canvas = document.getElementById("Canvas"); var Left = Canvas.style.left, Top = Canvas.style.top; x = Math.floor((x - Left.substring(0, Left.length - 2)) / BlockSize); y = Math.floor((y - Top.substring(0, Top.length - 2)) / BlockSize); if (y == SS_Y) { if (x == SS_X - 1) Move(-1, 0); else if (x == SS_X + 1) Move(1, 0); } else if (x == SS_X) { if (y == SS_Y - 1) Move(0, -1); else if (y == SS_Y + 1) Move(0, 1); }

}

function Move(DeltaX, DeltaY) { var NewX = SS_X + DeltaX, NewY = SS_Y + DeltaY; switch (Field[NewY * ColumnsQty + NewX]) { case 0: SS_X = NewX; SS_Y = NewY;

break;

case 1: GameOver(0);

break;

default: var ExtraX, ExtraY; if (DeltaY == 0) { ExtraX = NewX + DeltaX; ExtraY = NewY; } else { ExtraX = NewX; ExtraY = NewY + DeltaY;

}

if ((ExtraX < 0) || (ExtraX >= ColumnsQty) || (ExtraY < 0) || (ExtraY >= RowsQty) || (Field[ExtraY * ColumnsQty + ExtraX] == 2)); else {

Field[ExtraY * ColumnsQty + ExtraX] = 2;

var i, j; for (i = 0; i < ColumnsQty; i++) for (j = 0; j < RowsQty; j++) { if (Field[j * ColumnsQty + i] == 1) break; } if (i != ColumnsQty) { SS_X = NewX; SS_Y = NewY; Field[SS_Y * ColumnsQty + SS_X] = 0; GameOver(1); break; } } SS_X = NewX; SS_Y = NewY; Field[SS_Y * ColumnsQty + SS_X] = 0;

}

var PrevField = Field.slice(); for (var i = 0; i < ColumnsQty; i++) for (var j = 0; j < RowsQty; j++) { if (PrevField[j * ColumnsQty + i] == 1) { if (j == SS_Y) { if ((i == SS_X - 1) || (i == SS_X + 1)) { GameOver(0); break; } } else if (i == SS_X) { if ((j == SS_Y - 1) || (j == SS_Y + 1)) { GameOver(0); break; }

}

var DeltaI, DeltaJ; if (Math.random() < 0.5) { if (Math.random() < 0.5) DeltaI = -1; else DeltaI = 1; DeltaJ = 0; } else { DeltaI = 0; if (Math.random() < 0.5) DeltaJ = -1; else DeltaJ = 1; } var NewI = i + DeltaI, NewJ = j + DeltaJ; if ((NewI >= 0) && (NewI < ColumnsQty) && (NewJ >= 0) && (NewJ <= RowsQty) && (Field[NewJ * ColumnsQty + NewI] == 0)) { Field[NewJ * ColumnsQty + NewI] = 1; Field[j * ColumnsQty + i] = 0; } }

}

Paint();

}

function GameOver(Type) { Field[SS_Y * ColumnsQty + SS_X] = 1; SS_X = -2; SS_Y = -2;

Paint();

switch (Type) { case 0: alert("Сан Саныч пополнил ряды армии зомби и вместе с новыми товарищами под предводительством белочки вышел на улицы города сеять ужас и разрушение...");

break;

default: alert('Сан Саныч уничтожил всех зомби, но желание крушить и убивать не угасло. За окнами гипермаркета была ночь, освещенная огнями города. "А что, если там еще остался кто-то из НИХ?" - озвучила белочка мысли Сан Саныча. Маленькая пушистая лапка вложила ему в руку топор мясника и легонько подтолкнула в сторону двери, ведущей к выходу...'); } }

Только надо вручную подправить "Canvas.style.left" и "Canvas.style.top" на "Canvas.style.left" и "Canvas.style.top", потому что это какой-то глюк этого сайта.

Quote:
Come-from-Beyond писал(а):
Передвижение осуществляется кликаньем на клетку слева-справа-сверху-снизу от Сан Саныча.
Имхо, было бы еще удобнее если поддерживались клавиатурные клавиши управления курсора (вверх, вниз, влево, вправо).
Submitted by Victor on

Хорошая идея. Так и сделаю.

GameDev.by