Следующим этапом сделаем систему отображения тайлов на игровом поле. Мы предполагаем, что у нас есть тайлы разных типов: кирпичи там, бетон, вода, лёд, кусты.
И чтобы эти самые блоки рисовать на игровом поле, нужно ввести сущность карты и самих блоков.
Сущность карты:
class GameMap {
constructor() {
// Сетка 26x26 субтайлов
this.tileGrid = [];
for (let y = 0; y < GRID_SIZE; y++) {
this.tileGrid[y] = new Array(GRID_SIZE).fill(TILE_EMPTY);
}
// Карта для хранения состояния повреждений разрушаемых тайлов
this.damageMask = new Map();
// Флаг необходимости перерисовки фона
this.dirty = true;
}
}
Ну и в нашем основном классе надо карту создать:
/** @type {GameMap} */
let gameMap = null;
...
// в методе init
// Создаём и загружаем карту
gameMap = new GameMap();
gameMap.loadLevel(TEST_LEVEL_1);
// Рисуем фон (карта + рамка)
renderBackground(gameMap);
gameMap.dirty = false;
Не знаю, пока, на сколько такой формат хранения данных корректен и будет удобен в использовании в дальнейшем, но сейчас он по крайне мере очень нагляден и удобен для ручного левел дизайна.
Рисование блоков достаточно просто:
export function renderBackground(gameMap) {
const ctx = backgroundCtx;
// Очищаем весь фон
clearBackground();
// Рамка игрового поля
renderGameFieldBorder();
// Рисуем все непустые тайлы
for (let y = 0; y < GRID_SIZE; y++) {
for (let x = 0; x < GRID_SIZE; x++) {
const tileId = gameMap.getTile(x, y);
if (tileId === TILE_EMPTY) continue;
const tileDef = TILE_DEFS[tileId];
if (!tileDef) continue;
// Логические координаты → физические координаты на canvas
const px = GAME_FIELD_X + x * TILE_SIZE * GAME_SCALE;
const py = GAME_FIELD_Y + y * TILE_SIZE * GAME_SCALE;
const size = TILE_SIZE * GAME_SCALE;
ctx.fillStyle = tileDef.color; // цвет в самих тайлах пока храню
ctx.fillRect(px, py, size, size); // потом буду спрайты рисовать
}
}
}
Хранятся тайлы у меня вот таким образом:
TILE_DEFS = {
[TILE_EMPTY]: {
id: TILE_EMPTY,
name: 'empty',
blocksTank: false,
blocksBullet: false,
destructible: false,
overlay: false,
color: COLOR_EMPTY // эта вся фигня в константах забита
},
...
У сущности карты есть метод для загрузки из вот того текстового бреда, который чуть выше скинут
loadLevel(levelData) {
for (let y = 0; y < GRID_SIZE; y++) {
for (let x = 0; x < GRID_SIZE; x++) {
const char = levelData[y]?.[x] || '.';
this.tileGrid[y][x] = charToTile(char);
}
}
// Инициализируем damageMask для всех разрушаемых тайлов
this.damageMask.clear();
for (let y = 0; y < GRID_SIZE; y++) {
for (let x = 0; x < GRID_SIZE; x++) {
const tileDef = TILE_DEFS[this.tileGrid[y][x]];
if (tileDef && tileDef.destructible) {
this.damageMask.set(`${x},${y}`, DAMAGE_FULL);
}
}
}
this.dirty = true;
console.log(`Level loaded. Destructible tiles: ${this.damageMask.size}`);
}
function charToTile(char) {
switch (char) {
case 'B': return TILE_BRICK;
case 'S': return TILE_STEEL;
case 'W': return TILE_WATER;
case 'F': return TILE_FOREST;
case 'I': return TILE_ICE;
case 'E': return TILE_BASE;
default: return TILE_EMPTY;
}
}
И вот такой вот получается итог
В целом, уже похоже на правду и с этим можно работать.
После прошлого поста я что-то так проникся происходящим, что решил воссоздать ещё одну любовь детства. Но как говорил Маркус Персон: «Если вы не можете написать свой движок, то гавно вы, а не разработчики». Там, скорее всего, было как-о иначе, но суть такая. И да, с этой мыслью я в корне не согласен, но написать свой движок – задача, как минимум, интересная. Я решил, что аркадная игра для этого подходит, как ничто другое. По сути, некий аналог движка уже был реализован в тетрисе, но здесь нужна будет и какая-никакая физическая модель, и интеллект врагов и рендер всего этого безобразия в несколько слоёв и с ФПС побольше, чем 2 :)
Так что, приступим. Что нам нужно:
Просчёт физики
Работа ИИ агентов
Считывание действий игрока
Отрисовка результата работы предыдущих пунктов.
Для одного поста такая задачка звучит жирновато, поэтому, видимо, будет серия.
Я решил разделить рисования окружения (статичных объектов), врагов и игроков (динамических объектов) и UI на три разных канваса, которые просто повещены один поверх другого. Там можно будет проще и меньше перерисовывать.
Начинается наш код с проверки, готова ли страница к явлению миру нашего движка.
Если готова, то давай же скорее всё проинициализируем
Тут всё просто:
function init() {
console.log('Battle City Remake - Initializing...');
// Инициализация рендерера
initRenderer();
// Очищаем все слои
clearBackground();
clearForeground();
clearUI();
// Рисуем границу игрового поля и отладочную сетку
renderGameFieldBorder();
renderDebugGrid();
console.log('Initialization complete. Starting game loop...');
// Запускаем game loop
requestAnimationFrame(gameLoop);
}
Но понятное дело, что кода тут мало, потому что всё вынесено в отдельные методы.
Есть ли среди них хоть что-то интересное?
Ну, renderDebugGrid и renderGameFieldBorder одним названием уже говорят, что там происходит.
Логично, что самое интересное происходит где-то тут requestAnimationFrame(gameLoop);
Но давайте сначала заглянем в инициализацию рендера
Метод update содержит (ну, будет содержать) всю нашу игровую логику. Пока он только считает фпс и выводит его на экран для отладки.
function update(dt) {
// Пока пусто - здесь будет логика игры
// Подсчёт FPS для отладки
frameCount++;
fpsTimer += dt;
if (fpsTimer >= 1000) {
fps = frameCount;
frameCount = 0;
fpsTimer = 0;
// Обновляем FPS на странице
const fpsElement = document.getElementById('fps');
if (fpsElement) {
fpsElement.textContent = fps;
}
}
}
Ну и когда всё закончено, отрисовываем
function render() {
// Background canvas - перерисовывается только при изменении карты
// (пока только отладочная сетка, нарисованная в init)
// Foreground canvas - очищаем и рисуем сущности каждый кадр
clearForeground();
// TODO: Здесь будет рендер танков, пуль, эффектов
// UI canvas - очищаем и рисуем UI каждый кадр
clearUI();
renderUI();
}
То есть, по сути, ничего интересного, просто рисую полосочки и квадратики для UI
Результат выглядит вот так
Следующий пост будет посвящён второму этапу
И да, я упоролся и расписал себе полноценный план реализации на 13 этапов. Без ДизДока последнее время вообще не представляю как работать. А раз уж я в команде один, то сам себе и ТЗ пишу... Но лучше так, чем лепить полную отсебятину.
Вопросы замечания предложения в комментариях жду с нетерпением)
Вчера я остро ощутил, что очень давно не писал ничего простого, но функционального и интересного. А ещё я тут всё про игры да про игры, поэтому решил: пора!
Последнее, что я писал подобного – это змейку, которую можно было наблюдать во время обновлений сайта раньше (помните её?).
Да и ту на половину, а то и на две трети написал за меня чатГПТ. Поэтому я решил, что возьму нового подопытного и реализую всё сам. Мозг не должен забывать, как делать штуки...
В качестве основы решил взять HTML5 и ванильный JS, как технологию с самым дешёвым вариантом рендера, да и повторить, при желании, этот же алгоритм можно на любом другом движке.
Начнём с простого: нам понадобится текстовый редактор любой. Хорошо, если с подсветкой синтаксиса. Для самого простого можно взять Notepad++, для случаев чуть серьёзнее Атом или ВС код.
Создаём html страничку, она будет нашей точкой входа, рядом с ней создаём файлик стилей и основной наш скриптец. Забегая вперёд: стили нам не то, чтобы прям сильно нужны.
Дожидаемся, пока вся страница загрузится, потом инициируем игру
Пока что к самому алгоритму игры мы не приступили, это всё предварительные ласки.
В первую очередь давайте посмотрим на класс GameField.
class GameField {
constructor(width, height) {
this.width = width;
this.height = height;
this.blocks = [];
for (let i = 0; i < this.height; i++) {
let line = [];
for (let j = 0; j < this.width; j++) {
line.push(0);
}
this.blocks.push(line); //Заполняем массив ячеек поля нулями. поле по умолчанию пустое
}
}
checkLines = async () => { // тут мы проверяем, а есть ли линии, которые надо сбросить
for (let y = this.height - 1; y >= 0; y--) {
if (this.currentLineIsFill(this.blocks[y])) {
currentScore++; //плюсуем очки
for (let x = 0; x < this.width; x++) {
this.blocks[y][x] = 0;
redraw();
await sleep(LINE_CLEAR_ANIMATION_DELAY); // это просто для красивой анимации исчезновения
}
}
}
currentScore = getComboPoints(currentScore); // этот метод отдельно, там считаем прирос за комбо
}
currentLineIsEmpty = (line) => {
for (let x = 0; x < line.length; x++) {
if (line[x] === 1) { // если хоть одна ячейка заполнена, то идёт нахер
return false;
}
}
return true;
};
currentLineIsFill = (line) => {
for (let x = 0; x < line.length; x++) {
if (line[x] === 0) { // если хоть одна ячейка пустая, строка идёт нахер
return false;
}
}
return true;
};
moveLines = () => { // сдвигаем после удаления
let notEmptyLines = [];
for (let y = 0; y < this.blocks.length; y++) {
if (!this.currentLineIsEmpty(this.blocks[y])) {
notEmptyLines.push([...this.blocks[y]]); // сначала заполняем массив непустымы строками
}
}
let emptyLine = [];
for (let x = 0; x < this.width; x++) {
emptyLine.push(0); // потом досоздаём массив пустых строк
}
let newLines = []; // запиххиваем их в новый массив
for (let x = 0; x < this.height - notEmptyLines.length; x++) {
newLines.push([...emptyLine]);
}
for (let x = 0; x < notEmptyLines.length; x++) {
newLines.push([...notEmptyLines[x]]);
}
this.blocks = newLines;
}
}
Когда же мы будем всё это дёргать? И почему?
В методе, который описывает игровой цикл. Я постарался программировать так, чтоб даже при современном подходе можно было бы реализовать близкий по сути алгоритм на реальном камне, где, как известно многопоточность лишь выдуманная.
Раз в какое-то количество миллисекунд мы вызываем геймЛуп. «Почему же не сетинтервал», – спросит неокрепших неофит. А всё по тому, что это чревато как раз внезапной неконтролируемой асинхронностью, которая приведёт к гонке за ресурсы и будут беды. Поэтому метод будет вызывать сам себя только после того, как точно закончит.
const gameLoop = async () => {
if (gameMode !== GameMode.PLAYING || isLoopRunning) {
return;
}
isLoopRunning = true;
if (currentFigure === null || typeof currentFigure === 'undefined') { // у нас нет фигуры? Так давай её сделаем из того, что стоит в очереди
currentFigure = new Figure();
currentFigure.cells = nextFigure.cells.map(row => [...row]);
currentFigure.type = nextFigure.type;
currentFigure.states = nextFigure.states.map(state => state.map(row => [...row]));
currentFigure.rotationState = nextFigure.rotationState;
currentFigure.setStartPosition();
nextFigure.fillRandom(); // следующую фигуру херакнули в какую-нибудь новую рандомную
redrawNextFigure();
}
currentFigure.moveDown(); //уронили я одну клеточку
if (currentFigure.checkCollision()) {//пересеклисьс чем-нибудь?
currentFigure.moveUp(); //подняли обратно и зафиксировали с мировом пространстве
const overflow = currentFigure.placeToField();
currentFigure = null;
if (overflow) {
finishGame('top_out');
redraw();
isLoopRunning = false;
return;
}
await field.checkLines(); // все фигуры на своих местах, можно проверить, как там у нас дела
score += currentScore;
scoreEl.innerText = score;
currentScore = 0;
field.moveLines(); // сдвинем, если надо сдвинуть
}
redraw();
isLoopRunning = false;
if (gameMode === GameMode.PLAYING) {
tickTimeout = setTimeout(gameLoop, getCurrentTickDelay()); // снова запускаем всё сначала
}
};
В целом, осталось только понять, что же такое фигура.
Сама геморная часть. Там больше всего буковок.
Фигура - это сущность, в которой хранится информация о том, какой она формы и как её крутить.
class Figure {
constructor() {
this.cells = [
[0],
];
this.x = 2;
this.y = -5;
this.rotationState = 0;
}
moveDown = () => {
this.y++;
};
moveUp = () => {
this.y--;
};
moveLeft = () => {
this.x--;
if (this.checkCollision()) {
this.x++;
}
}
moveRight = () => {
this.x++;
if (this.checkCollision()) {
this.x--;
}
}
fall = () => {
while (!this.checkCollision()) {
this.y++;
}
this.moveUp();
};
checkCollision = () => {
for (let i = 0; i < this.cells.length; i++) {
for (let j = 0; j < this.cells[i].length; j++) {
let cellX = j + this.x;
let cellY = i + this.y;
if (this.cells[i][j] === 0) {
continue;
}
// Проверяем границы по X всегда (независимо от Y)
if (cellX < 0 || cellX >= field.width) {
return true;
}
// Для клеток выше видимой области не проверяем коллизии с полем
if (cellY < 0) {
continue;
}
// Проверяем нижнюю границу и коллизии с заполненными клетками
if (cellY >= field.height) {
return true;
}
if (field.blocks[cellY][cellX] === 1) {
return true;
}
}
}
return false;
};
rotate(withCollisions = true) {
const from = this.rotationState;
const to = (from + 1) % this.states.length;
const key = `${from}>${to}`;
const kickSet = (this.type === "I")
? SRS_KICKS.I[key]
: (this.type === "O" ? SRS_KICKS.O[key] : SRS_KICKS.JLSTZ[key]);
const originalX = this.x;
const originalY = this.y;
let rotated = this.states[to];
if (!withCollisions) {
this.cells = rotated;
this.x = originalX;
this.y = originalY;
this.rotationState = to;
return;
}
for (const [dx, dy] of kickSet) {
this.cells = rotated;
this.x = originalX + dx;
this.y = originalY - dy;
if (!this.checkCollision()) {
this.rotationState = to;
return;
}
}
this.cells = this.states[from];
this.x = originalX;
this.y = originalY;
}
placeToField = () => {
let overflow = false;
for (let i = 0; i < this.cells.length; i++) {
for (let j = 0; j < this.cells[i].length; j++) {
let cellX = j + this.x;
let cellY = i + this.y;
if (this.cells[i][j] === 0) {
continue;
}
if (cellY < 0) {
overflow = true;
continue;
}
if (cellY >= field.height || cellX < 0 || cellX >= field.width) {
overflow = true;
continue;
}
field.blocks[cellY][cellX] = this.cells[i][j];
}
}
return overflow;
};
setStartPosition = () => {
this.x = Math.floor(field.width / 2) - Math.floor(this.cells[0].length / 2);
if (this.type === "I" && this.rotationState === 1) {
this.y = -2;
} else if (this.type === "I") {
this.y = -4;
} else if (this.type === "O") {
this.y = -2;
} else if (this.rotationState === 3) {
this.y = -2;
} else {
this.y = -3;
}
};
fillRandom = () => {
let figure = FIGURES[Math.floor(Math.random() * FIGURES.length)];
this.cells = figure.figure.states[0].map(row => [...row]);
this.states = figure.figure.states.map(state => state.map(row => [...row]));
this.type = figure.type;
this.rotationState = 0;
let rotateSteps = Math.floor(Math.random() * 4);
for (let i = 0; i < rotateSteps; i++) {
this.rotate(false);
}
};
}
Тут, конечно, кода дофига и надо объяснить, что тут происходит. Суть в том, что поворот в тетрисе – это прям отдельная задачка. Я её для себя упростил максимально, создав «спрайты» фигур во всех положениях заранее.
А ещё есть такая штука как SRS – это прям общепринятый стандарт вращения фигур. Специальные таблицы описывают как необходимо проверять смещение фигур в пространстве игрового поля при переходе из одного состояния в другое, на случай столкновения со стенами или существующими блоками в момент вращения. Я, опять-таки, эту часть упростил максимально, вырезав очень много из стандарта, так как у меня, как минимум, нет вращение против часовой стрелки.
Логика такая: после поворота к фигуре применяются смещения по иксу и игрику по очереди из массива, сначала 0-0 (не смещается), потом, к примеру 0-1 и так далее. За идеальное состояние, которое в данный момент всех устраивает, применяется то, после которого проверка коллизии фигуры показывает, что никто ни с кем не столкнулся. Если ни один из вариантов не подошёл, значит поворот не случился.
Классические таблицы подразумевают матрицы фигур одинакового размера и квадратные по своей сути. Я тут тоже отошёл от стандарта,
Как это в итоге играется
По коду там есть у меня есть усложнение с увеличением скорости падения фигур за каждые 30 полученных очков, сохранение рекорда и прочая мишура, которая к основному алгоритму отношения уже не имеет.
Как грицца: понятно, что нифига не понятно, так что спрашивайте, господа и дамы, отвечу на недостающие вопросы)
Прошлую неделю я с новостями профилонил, потому что писал фоксфрейм, сейчас снова возвращаюсь с подборкой того, что мне показалось самым интересным в индустрии.
Один модер против всей системы
Спойлер: он не победил.
Есть дяденька по имени Люк (Luke Ross), он делает уже несколько лет VR моды к разным популярным играм. В целом весьма неплохо делает, все довольны. Все, кроме авторов самих игр. Они говорят: «А чё это ты за свою работу деньги берёшь? Только мы имеем право получать деньги за то, что касается наших игр! Удоли!». Словил он страйк сначала за мод к киберпанку, потом за гостранер. В итоге он обиделся на весь этот корпоративный сброд и удалил все свои 40 модификаций со страницы на Патреоне.
Ситуация двоякая и интернет не встал единым фронтом на защиту модера и как история будет развиваться, пока не понятно (бьюсь об заклад, что никак).
Авторы «Диабло» делают «Диабло дома» за пределами близард
Moon Beast Productions – контора, которую основали дяди и тёти, которые когда-то раньше работали в метелице над диаблами. Теперь они делают новую игру Darkhaven, конечно же, в том же самом жанре
Пока это не более, чем анонс. Авторы планируют на днях или раньше начать сбор средств на кикстартере.
Новый героев помогает делать автор вселенной
HoMM olden era выглядит супер многообещающе (по крайней мере для меня). Но визуальный стиль – это далеко не всё, что нужно игре. Поэтому разработчики пригласили в качестве творческого консультанта Джона Ван Канегема, автора Might and Magic
Ремейк песков времени больше не ремейк
Юбисофт окончательно отчаялась и отменила долгострой, который многие фанаты с нетерпением ждали.
У Принца Персии не лучшие времена...
Stop Killing Games, возможно, даже выстрелит
Инициатива, если кто-то не в курсе, призывает разработчиков всех мастей обеспечить возможность играть в игры даже после того, как они перестали быть коммерчески успешными для издателей.
На сегодняшний день петиция с инициативой собрала порядка 1.3 миллионов подтверждённых пользователей, а в ЕС принято такие петиции официально рассматривать в еропарламенте.
Не далее как вчера товарищ @ZenitTTLMir1B писал о сложности загрузке видео при нестабильном соединении.
Я ночью всобачил на хостинг поддержку дозагрузки и отслеживания наличия сети.
Вот это видео было залито с принудительным разрывом соединения, переключением между сетями в процессе. Эксперимент считаю удавшимся, но если у вас возникнуть проблемы, дайте знать, будем чинить!
Студия Kinetic Games открыла издательское подразделение
Ребятки, разработавшие кооперативный ужастик Phasmophobia подумали и решили, что помощь начинающим разработчикам – это благое дело.
Даниель Найт, тот самый дяденька, который в одно лицо в своё время трудился над той самой фазмофобией, пришёл к выводу, что ему бы в тот момент такая поддержка ну вот вообще не помешала.
От себя лично неистово плюсую мужику, так как мой ход мыслей ровно точно такой же.
Лариан сказали, что решили отказаться от ИИ
Я ранее уже писал о скандалах, навалившихся на разработчиков из-за заявлений, что они периодически пользуются нейросетями для ускорения процесса. Интернет взбурлил говнами, и студия решила «ну его нахер». Заявили, что от греха подальше не будут больше так делать.
А мне лично кажется, они просто сказали разъярённой толпе то, что та хочет услышать. Отказываться от удобного инструмента просто потому что кто-то считает его «фу» – выстрел себе в колено.
Ну и кстати, о том, как толпа любит кого-нибудь в чём-нибудь обвинить.
Авторов Lords of the Fallen 2 обвинили в плагиате
Они показали картинку, как будет выглядеть один из персонажей.
вот так
И интернет такой: «О, я знаю откуда это спижжено!»
от сюда
Но глава студии сказал, что любители заговоров могут идти топтать газон в другом месте, а дизайн был разработал за долго до анонса НайтРейна (именно оттуда второй персонаж), а что до сходства, то... Ну... Они оба в броне и у них есть меч...
Вышла в релиз Мор 3 (Pathologic)
Не то, чтобы это прям полноценная третья часть, это сюжетная кампания за Бакалавра. То есть теперь у игроков есть возможность оценить весь контент ремейков Мора Утопии.
Детализация – это процесс, которым занимается уже не столько левел дизайнер, сколько левел артист. Напомню, что в англоязычной терминологии слово дизайн не про «красиво», а про «спроектировано». Соответственно красотой занимается художник по окружению, опираясь на результаты тестов, проведённые в результате построения грейбоксов и позднее вайтбоксов.
По итогу у нес есть вот такая невзрачная, но уже функциональная локация
Начинаем наваливать на неё детальки
И расставлять свет.
Свету будет посвящён отдельный пост, так что тут не буду заострять на нём внимание. Но основная мысль в украшении локации заключается в том, что нужно наваливать на неё деталей, до тех пор, пока влезает и при этом не нарушает общую художественную задумку и не портит геймплей.
Так выглядит локация в той игре, откуда я её срисовывал.
Чем отличается хорошая локация от плохой? Чет отличаются хорошие локации в старых играх от хороших локация в новых?
Количеством деталей. Чем больше каких-то мелкий элементиков, текстурок, деталей будет в поле зрения игрока, тем с большей охотой он готов будет поверить в увиденное.
При этом нужно понимать, что в некоторых случаях излишняя детализация может пойти во вред игровому процессу.
Mirror’s Edge. Тут всё ещё есть детали, позволяющие поверить в этот мир, но материалы и текстуры сделаны максимально стирильно.
Думаю, нет 100% верного совета, как нужно делать, так как это сильно зависит и от художественного стиля вашей игры и от механик и от отзывов конечных игроков.
Наверное мне просто хочется вывалить всё то, что сохранилось у меня в закромах. Я отчётливо понимаю, что есть те вещи, которые ну никак не получится реализовать здесь и сейчас, а потом... А потом, когда, скорее всего, появятся ресурсы на реализацию, я с большим удовольствием потрачу их на что-то другое.
Что же такое Dissidentity? Вообще, это игра слов Диссидент и Идентичность.
Как родилась идея и что это вообще всё значит?
Ещё на заре моих попыток делать игры, в одно прекрасно утро (может ли оно быть прекрасным, если я тогда работал в офисе?) я поделился с коллегой своей страстью. Коллега зацепился за мысль и вместе спустя небольшой мозговой штурм было принято решение, что нужно делать хоррор?
Почему? Да потому что страшилка – это жанр, который требует меньше всего ресурсов и его вполне реально поднять в 1-3 человека в не слишком длинные сроки. Я должен был заниматься непосредственно производством, коллега ведением проекта, тестированием и небольшой помощью в производстве, его жена должна была стать сценаристом (я в тот момент времени ещё не писал книги, а если и писал, то об этом никто кроме жены и пары друзей не знали).
Звучало реально и правдоподобно, но тут на сцену вышли амбиции (а моя безудержная фантазия). Я не могу позволить себе делать что-то заурядное, мне скучно, поэтому я подумал: «А что если во главе сюжета будет стоять раздвоение личности?». Это та самая идентичность в названии (Диссоциативное расстройство идентичности – настоящее название заболевания (Dis - в названии в том числе отсюда, а не только из слова диссидент)).
Интересно? Допустим. Мне показалось этого мало. Мы играем за обычного преподавателя в университете. Игровой процесс начинается именно с того, что мы буквально должны провести лекцию студентам, но потом, покинув аудиторию, персонаж бы оказывался в какой-то искажённой версии универа. Как после апокалипсиса, вызванного открытием врат в Ад. И задачей игрока с этого момента будет поиск выхода из опасного для жизни места. Какие-то фантасмагоричные монстры, ядовитый газ, меняющееся пространство становятся препятствием на пути к выходу, но вот, наконец, выход найден, персонаж открывает дверь и обнаруживает себя на крыше здания. Вокруг собралась толпа зевак, полицейские пытаются арестовать героя, а он, дабы не быть арестованным решает сбросится с крыши. Конечно же ни игрок ни герой ничерта не понимают. Падение с крыши происходит случайно, оступился дяденька от растерянности. Но он не умирает, а падает в какое-то липкое тёмное болото, которое расопложилось рядом с домом, где прошло детство главного героя.
И там его ждут новые испытания. Суть в том, что мы, как игрок, всегда играем за одну и ту же личность. Просто игра пытается фантазировать на тему, что происходит с той личностью, которая в данный момент неактивна. И действие, соответственно, происходит внутри больного сознания героя, где он должен победить монстров и боссов, отражения реальных проблем, которые и стали причиной того, что он поехал кукушечкой.
Что же пошло не так?
Жена коллеги, будучи неопытной писательницей, да к тому же, не особенно проникшаяся идеей, достаточно быстро выгорела. Коллега только и делал что думал о том, как найти издателя/инвестора/спонсора. Ведением проекта не занимался даже чуть-чуть. Ну и я очень быстро пришёл к выводу, что каши тут не сварится, и проект забросил, однако, для него было написано несколько заготовок суандтреков. Как своими силами, так и с помощью товарища. И я сделал самую первую локацию. Дальше дело не дошло...
Даниэль Вавра (тот, который киндом кам натворил) решил вступиться за Свена Винке (Лариан) в сраче по поводу нейросетей. Он не просто сказал, что, мол, ай-ай-ай. Он подошёл к ещё даже не тлеющему костру, кинул в него бутылку с бензином и хохотал.
Основной посыл был в том, что: «Вы наезжаете на одну команду за то, что она делает тоже самое, что и ВСЕ вообще остальные».
Поможет ли это людям считающим, что можно линчевать кого угодно за использование инструмента, который им не нравится, понять, что они что-то делают не так? Время покажет.
Серия Fifa больше не про спортсим
Правами на издание игр по бренду Фифа теперь принадлежат Нетфликсу и они решили, что теперь это будет казуальная дрочильня с управлением с телефона. Как сказали сами Нетфликс: чтоб в футбол могли играть все, а не только задроты (ну там другой немного текст, но посыл такой).
Самой бюджетной СтимДек больше не будет на рынке
Валв не сильно так переживая просто молча сняла её с производства. Поигрались, и хватит.
Вышла новая LTS версия Unity
Из новшеств:
Улучшили производительность. Заявлено, что в новой версии скорость билда больших приложений возросла в два раза, а TypeTree-рантайм стал потреблять на 99% меньше памяти.
Platform Toolkit. Новый пакет даёт единый удобный API для написания базовой инфраструктуры игр на все основные платформы. Обещают, что станет удобнее добавлять достижения, делать сохранения и интеграцию с аккаунтами. Обещается поддержка: Windows (включая сервисы Steam), Xbox Series и One, PlayStation 5, Android, iOS и Нинтендо Свитч (и первая и вторая).
Новая версия OpenXR 1.1 для Android умеет динамически скейлить разрешение игры для сохранения производительности.
А вы сразу обновляете свои проекты, как только выходит новая версия движка?
P.S. Новость не прошедшей недели, но я тормоз и сам только сейчас узнал.
У Titan Quest выходит новая глава
Игра всё ещё в раннем доступе, но разработчики вываливают большой контентный шмат.
Новые локации, задания, умения и т.д. Всё вполне ожидаемо.
Беседка обновляет свой движок Creation Engine
Движку, на котором Bethesda делает свои игры, примерно миллиард с половиной лет. Одни и те же баги тянутся шлейфом ещё с Обливиона. И вот прошёл слушок, что Майкрософт активно помогает ребятам из беседки обновить этот движок, внедрив в него куски анреал энджина. Хорошо ли это? Тут только время покажет, но звучит интересно.
Большой апдейт для Архолоса
Вы не знаете что это? Забавно... Юридически – это мод на вторую Готику. Фактически – это буквально новая часть классической Готики, этакий фанатский вбоквел, официально одобренный издателем. В фанатской среде считается, что это лучшее, что происходило с серией с момента релиза Ночи Ворона.
Вот такой список обновлений обещают:
Хардкорный режим;
Новые сюжетные линии и квесты;
Расширения возможностей кастомизации протагониста, включая не только внешность, но и способности;
Свежие локации и предметы;
Улучшение искусственного интеллекта противников;
Новые случайные встречи;
Новые мини-игры;
Ребаланс;
Расширение боевой арены;
«Множество сюрпризов».
Ну на этом, пожалуй, и всё. Индустрия перед праздниками чуть затихла. Новые новости (а может и старости) уже после Нового года.
Divinity: Original Sin 2 Стала доступна на всех современных платформах
Лариан вывалили трейлер
Там не показывают ничего интересного, но он посвящён самому факту, что в красивую классную и интересную игру можно сыграть и на Nintendo Switch 2, Xbox Series X/S, & PlayStation 5.
Изометрических хоррор Graft
Весьма занимательный проект появился на горизонте. Правда, пока только в виде трейлера.
Игру анонсировали в прошлом году, но пока данных о релизе нет.
История в игре весьма стандартна: летели-летели себе на корабле-ковчеге, всё было хорошо. А потом перестало быть хорошо и как началось нехорошо, что аж плохо стало. Теперь приходится выживать.
Особенность проекта состоит в том, что герой по ходу прохождения может прокачиваться, приращивая к себе куски поверженных биомеханических врагов. И всё бы ничего, но эти аугументации могут хранить отпечаток сознания прежнего владельца и тут вопросик: кем тогда станет герой к концу прохождения?
Итоги года в стим
Валв запустила специальную страницу, где можно посмотреть итоги года. Во что и как много вы играли. Делитесь, господа и дамы) Будет интересно посмотреть.
Ни недели без срача. ИИ опять
Свен Винке дал интервью, в котором обмолвился, что люди в студии Лариан пользуются ИИ для прототипирования или наброски каких-то базовых механик/текстов/артов для заглушки на начальном этапе работы или для вдохновения.
Но интернет от этого взбурлил говнами и начал закидывать как самого Свена так и его студию фекалиями, мол, какой он негодяй.
В соцсети Х ещё с прошлого срача люди волну нагоняли, а сейчас и вовсе развязалась баталия, в которой то и дело приводятся аргументы и за и против использования нейросетей.
Так шо там с пончиками?))
там дырки
Очень красиво. И цвета вод какие!