Статью написал в рамках подготовки к пятничному игровому джему (GMTK Game Jam 2023). Никогда в них не участвовал, вот и решил проверить, что успею запилить хоть что-то за пару дней. Поболейте за меня или сами поучаствуйте. Статья - рефлексия на тему игр и обучения, а игра - результат этой рефлексии. В статье так же расскажу наиболее простой способ написания игры на HTML5, инструменты и современные подходы.

Игра

Немного майевтики. Прежде чем начать, ответим на вопрос - зачем делать игру вообще? И что такое игра?

Игра - инстинктивный способ обучения, мы делаем игру для того, чтобы чему-то научить. Но как? Исходя из теорий бихевиоризма - через позитивное и негативное подкрепление.

Если игроку не интересно чему-то учиться - нужно заинтересовать его механиками (mech; megʰ - мочь), т.е. "мощью" игры. Если игрок "переобучен" - игра ничему не сможет научить и будет скучно. Если игрок "не до обучен" - у него может не быть тех навыков и знаний, которые требуются для игры. Крайние примеры: "Игры про Кузю" и "Dawrf Fortress".

2048
2048

Хороший пример: игра 2048. Она учит степеням двойки, предсказывать свои действия, принимать стратегические решения, свайпать. Но игра использует механику вызова (challenge): "Набери 2048".

Время койота
Время койота

Игрок осознает и эмоционально реагирует на механики (re - обратно, *ag- гнать, двигать). Сама тема эмоций - огромна, мы классифицируем их все на два типа. Позитивные - обучение прошло успешно, негативные - есть проблемы. Если игра не объясняет механики, то они называются скрытыми, на них игрок реагирует бессознательно. Например "Время койота".

Механики

Найди Вальдо
Найди Вальдо

Помимо обучения игры дополняют эстетическими, социальными и материальными механиками. Социальные вызывают эмоции чувства принадлежности, чувства признания; материальные - азарт и т.д. Чаще всего - механики берут уже из известных игр, которые себя зарекомендовали, т.к. это бесконечно проще, чем изобрести новую, успешную механику. Обычно, совокупность механик называют жанр игры. Например, жанр "квест" (quest - поиски). Как следует из названия - это механика поиска чего либо. Например, "Найди Вальдо".

Интерактивность (interaction, inter - посреди, act - действие) - это про события. Игра запустилась, прошло время, тык пальцем/мышкой в экран. На эти события есть реакции игры (re - обратно, act - действие). В контексте игрока, событием будет появление на экране двух прямоугольников, а его реакцией будет эмоция (emotion, e - наружу, moveo - двигаться). В зависимости от эмоции - действие, событие в контексте игры. Больше интерактивности - лучше раскрывается механика.

Геймдизайн

Допустим, мы хотим научить игрока нажимать на закрашенный прямоугольник на экране. Будем рассматривать два события: игрок успел нажать на прямоугольник, или - не успел. Если игрок успел - успокаиваем и удивляем, если нет - злим. Допустим, синий - безопасный и приятный цвет (спокойствие ????), красный - опасный и неприятный цвет (злость ????). игрок справился отлично - постараемся его удивить зеленым ????. И на добивочку фиолетовый ????.

Сама тема цвета и его применения - огромна. Например, в США есть розовые тюрьмы. Согласно исследованиям - человеческий глаз наиболее восприимчив к зелёному участку спектра. Красный - кровь, синий - небо. Но это уже из области знаний о графическом дизайне. Мало кто замечал, но у многих успешных компаний синий логотип. Я инженер, поэтому буду использовать палитру "Инженерная".

Механика

Согласно отчету Contentsquare 2021 Digital Experience Benchmark, среднее по больнице время просмотра одной страницы составляет 54 секунды.

Считаем количество успехов (successes) и неудач (fails). Если игрок справился, т.е. достиг максимального успеха (wins) - игрок обучен, игра окончена. Если же игрок не справляется - то ему нужно помочь. Если игрок достиг максимального числа неудач (looses) мы поможем ему и подставим прямоугольник под указатель, чтобы у него точно получилось, и сбрасываем число неудач. Это нужно, чтобы улучшить понимание механики. Таким образом мы объясняем, как оно работает. Есть вероятность, что мы не смогли вызвать эмоцию - тогда и сама механика в целом не будет работать. Помним закон Мерфи. Палитра "Инженерная"
Палитра "Инженерная"

Чтобы проверить, что игрок действительно научился - будем считать, сколько раз он попал. Чем больше попыток потребуется - тем большим упорством должен обладать игрок и зависит от заинтересованности игрока. Будем считать, что ожидаемый интерес к нашей игре 10% и игрок проведет в игре 5.4 секунды.

Считаем количество успехов (successes) и неудач (fails). Если игрок справился, т.е. достиг максимального успеха (wins) - игрок обучен. Если же игрок достиг максимального числа неудач (looses) мы поможем ему и подставим прямоугольник под указатель, чтобы у него точно получилось, и сбрасываем число неудач. Это нужно, чтобы улучшить понимание механики. Это оригинальная механика, поэтому я не знаю, как она себя поведет, тем интереснее.

Поощрение => Эмоция
Поощрение => Эмоция

Есть вероятность, что мы не смогли вызвать эмоцию - тогда и сама механика в целом не будет работать. Помним закон Мерфи. Обычно просто добавляют надпись, стрелки, вызывающей желание нажать элемент (кнопка) и т.д. Для того, чтобы закрепить обучение - добавим механику поощрения. Если игрок научился и количество успешных попыток достигло максимума (wins), мы наградим игрока зелёным.

Для более ярких эмоций - воспользуемся звуком. Для этого мы будем использовать простой онлайн секвенсор (https://onlinesequencer.net/), создадим по звуку на каждое нажатие, по аналогии с цветом.

Реализация

Создадим два файла: index.html и script.js. Названия файлов на английском, как и код игры. index.html будет использоваться для запуска игры (будет открываться в браузере). Файл представляет собой документ, в котором есть тело (body) и файлы скриптов (script). Пока мы будем использовать только файл script.js. Нужно добавить две строчки в файл html:

<body></body>
<script src="script.js"></script>

Для начала, нужно настроить документ. Добавим заголовок страницы, холст, выровняем. Файл script.js хранит код игры на языке JavaScript. В первую очередь, нам нужно создать элемент холст (canvas), на котором мы будем рисовать игру. Затем, добавляем холст в тело документа (document).

Слово "контекст" означает ситуацию, в которой что-то происходит. Игра двухмерная, поэтому и рисовать мы будем в двумерном 2d контексте (context, 2D, Dimensional - измерение). Добавляем в script.js:

Подготовка страницы
const canvas = document.createElement('canvas')  // Создали холст
const context = canvas.getContext('2d') // Получаем 2d контекст
document.body.appendChild(canvas)  // Добавляем холст в тело документа
canvas.width = screen.width // Ширина холста по ширине экрана
canvas.height = screen.height // Высота холста по ширине экрана
//Это нужно, чтобы холст располагался в документе ровно
canvas.style.left = 0
canvas.style.top = 0
canvas.style.position = 'absolute'
//Если не во весь экран - скрываем скролл
document.body.style.overflow = 'hidden'
//Заголовок станицы
document.title = 'Game'

Следующий этап - определить значения всех переменных в игре. Сколько побед, успехов требуется, пути к файлам звуков и т.д. Я предпочитаю разделять функции от данных, поэтому каждый блок игры поместим в отдельный JS объект. Описываются они в формате JSON.

Данные
//Конфигурация уровня
const level = {
    score: 0,
    //Среднее время игры
    defaultTime: 5400,
    //Цвет текста нового уровня
    levelUpColor: '#ff00ff',
    //Цвет текста очков цепочки
    scoreColor: '#000000',
    easy: {
        //Количество очков до следующего уровня
        scoreUp: 10,
        currentPosition: 0,
        min: [100, 100],
        max: [400, 300],
        step: [100, 100],
        positions:[ [100,100], [100,200], [200,200], [300,200] ],
        lastTime: null,
        bestTime: null,
    },
}
//Конфигурация базы
const base = {
// Положение и размер прямоугольника
    x: level.easy.positions[0][0], 
    y: level.easy.positions[0][1], 
    width: 100, 
    height: 100,
// Положение и размер второго
    x2: level.easy.positions[0][0],
    y2: level.easy.positions[0][1],
    width2: 10, 
    height2: 10,
//Заливка
    strokeStyle:'#000000',
//Закраска
fillStyle:'#aaaaaa',
//Закраска при успехе
    fillStyleSuccess:'#aaffaa',
    fillStyleFail:'#aaaaaa',
}
//Конфигурация механики
const mechanic = {
    //Цвет успокоения
    successColor: '#0000ff',
    //Цвет победы
    winColor: '#00ff00',
    //Цвет поражения
    failColor: '#ff0000',
    //Закраска экрана
    eraserColor: '#ffffff20',
    // Количество победных нажатий
    wins: 3,
    // Количество неудачных нажатий
    looses: 3,
    successes: 0,
    fails: 0,
    sizeStep: 20,
    winner:false,
    hits: 0,
    success: false,
    cursor: { x: 0, y: 0 },
    size: 0,
    overwinSizeStep: 10,
    overwin: 0,
    baseWidth: base.width,
    baseHeight: base.height,
    pointerShrink: 0.85,
}
//Пути к звукам
const audio = {
    fail:'sfx/fail.mp3',
    level:'sfx/level.mp3',
    success: 'sfx/success.mp3',
    win:'sfx/win.mp3',
    loose:'sfx/loose.mp3',
    score:'sfx/score.mp3'
}

2D
2D

Нарисуем на холсте два прямоугольника (rectangle, rect). Один черный (#000000), другой - серый (#aaaaaa). Цвета задаются в 16-ричным числом (hexidecimal; hex). Расстояния на холсте измеряются в пикселях (pixel; px), положение измеряется от верхнего левого угла, двумя значениями с названиями икс (x) и игрик (y). Соответственно, у прямоугольника есть положение на холсте (x,y), ширина и высота (width, height), цвет (color). Он может быть обведенным (stroke) или закрашенным (fill). О том, как использовать 2D контекст холста в WEB, а так же - полное руководство.

База
//Рисуем базу
function drawBase() {
    context.strokeStyle = base.strokeStyle // Цвет обводки
    context.fillStyle = base.fillStyle // Цвет заливки
    context.fillRect(base.x, base.y, base.width, base.height) // закрашиваем
    context.strokeRect(base.x2, base.y2, base.width2, base.height2) // обводим
}

Для ощущения механики прогресса - будем закрашивать холст прозрачным белым цветом на каждое нажатие, из-за чего предыдущие попытки будут растворяться. Для отличника - будем закрашивать постоянно по времени. В среднем, в играх уровень интерактивности графики около 60 обновлений (кадров) в секунду (FPS, frames per secord). Для этого мы создадим событие по времени: каждые 1000/60, где 1000 - количество миллисекунд в секунде (милли-, milli-, одна тысячная), 60 - FPS. Т.е. каждые 16.66.. миллисекунд будет происходить закрашивание экрана прозрачным белым.

Заливка прозрачным
function fade(){
    context.fillStyle = mechanic.eraserColor // Цвет заливки
    context.fillRect(0, 0, canvas.width, canvas.height) // закрашиваем
    //Базу и очки оставляем, т.к. не все поймут
    showMaximumScore()
    drawBase()
}

Регистрируем событие нажатия на экран. Событием будет нажатие указателем (pointwerdown) на тело документа. Следствие события (символ ⇒) будет меняться в зависимости от того, куда игрок попал. У указателя тоже есть положение x и у, поэтому нам нужно проверить, что указатель (точка) находится внутри прямоугольника. Есть хорошая статья на эту тему, расписывать не буду. Если попал указателем в прямоугольник в x,y с шириной и высотой width и height - попытка успешная, мы подкрепляем синим. Если не попал - красным. При каждом нажатии нарисуем на экране прямоугольник попадания в точке указателя. При попадании - сбрасываем промахи и наоборот.

Цифр количества успехов (successes) и неудач (fails) игрок не видит. Чтобы игрок чувствовал прогресс (progress, pro - вперед, gradi - идти). но нужно ему дать об этом знать. Для этого будем увеличивать размер нарисованного попадания в зависимости от successes и fails подряд. Если игрок превысит количество ошибок - закрашиваем предыдущий прямоугольник красным и рисуем новый, под указателем. Если игрок справился с обучением - рисуем попадание зеленым.

Событие при клике
function onClick(e) {
    fade()
    base.x2 = e.x - base.width2 / 2
    base.y2 = e.y - base.height2 / 2
    mechanic.hits++
    mechanic.cursor = getCursorPositionOnCanvas(canvas, e)
    mechanic.success = 
        mechanic.cursor.x >= base.x && mechanic.cursor.y >= base.y
        && mechanic.cursor.x <= base.x + base.width
        && mechanic.cursor.y <= base.y + base.height
    if(mechanic.success){
        new Audio(audio.success).play()
        mechanic.fails = 0
        mechanic.successes++
        if(mechanic.successes >= mechanic.wins){
            new Audio(audio.win).play()
            mechanic.overwin = 1 + mechanic.successes - mechanic.wins
            mechanic.size = mechanic.size + mechanic.sizeStep
            mechanic.fillStyle = mechanic.winColor
            level.easy.currentPosition++
            level.easy.currentPosition = level.easy.currentPosition % level.easy.positions.length
            if(level.easy.currentPosition === 0){
                mechanic.winner = true
                if(level.easy.lastTime===null){
                    level.easy.lastTime = new Date()
                } 
                else {
                    level.easy.bestTime =  new Date() - level.easy.lastTime
                }
            }
            base.fillStyle = base.fillStyleSuccess
            drawBase()
            const position = level.easy.positions[level.easy.currentPosition]
            base.x = position[0]
            base.y = position[1]
            base.x2 =  position[0] + base.width / 2 -  base.width2 / 2
            base.y2 = position[1] + base.height / 2 -  base.height2 / 2
            base.fillStyle = base.fillStyleFail
            drawBase()
        }
        else{
            mechanic.fillStyle = mechanic.successColor 
            mechanic.size = mechanic.successes / mechanic.wins * mechanic.sizeStep
        }
    }
    else{
        base.fillStyle = base.fillStyleFail
        new Audio(audio.fail).play()
        level.easy.currentPosition = 0
        level.easy.lastTime = null
        mechanic.fails++
        mechanic.successes=0
        if(mechanic.fails >= mechanic.looses){
            new Audio(audio.loose).play()
            mechanic.winner = false
            mechanic.fails = 0
            context.fillStyle = mechanic.failColor
            context.fillRect(base.x, base.y, base.width, base.height)
            base.x = mechanic.cursor.x - base.width /2
            base.y = mechanic.cursor.y - base.width /2
            drawBase()
        }
        if(mechanic.winner){
            drawBase()
        }
        if(mechanic.overwin > 0){
            mechanic.successes=mechanic.wins
            mechanic.overwin = 0
            mechanic.size = 0
            context.fillStyle = mechanic.failColor
            context.fillRect(base.x, base.y, base.width, base.height)
            drawBase()
        }
        mechanic.size = mechanic.fails / mechanic.looses * mechanic.sizeStep
        mechanic.fillStyle = mechanic.failColor
    }
    context.fillStyle = mechanic.fillStyle
    context.fillRect(mechanic.cursor.x - mechanic.size/2, mechanic.cursor.y - mechanic.size/2, mechanic.size , mechanic.size) 
    if(level.easy.bestTime !== null){
        showText(e)
    }
}

На этом базово обученного игрока уже можно протестировать, провести экзамен. Будем перемещать прямоугольник в новую точку, ожидая попадания с первой попытки. Повторим это несколько раз и в конце дадим оценку (score) за прожатую цепочку целей. Рассчитаем оценку как время, за которое игрок прожал все цели, чем быстрее - тем лучше. Если успешно - выведем оценку на экран.

Показать текст очков и победы
function showText(e) {
    new Audio(audio.score).play()
    const speed = level.defaultTime / level.easy.bestTime
    const rating = 1 + Math.round(speed * 5)
    const fontSize = (10 + 15 * speed)
    context.font = fontSize + "px serif"
    context.fillStyle = level.scoreColor
    context.fillText('+' + rating + '!', e.x, e.y)
    level.easy.bestTime = null
    level.easy.lastTime = new Date()
    if (rating > level.easy.scoreUp) {
        new Audio(audio.level).play()
        document.title = 'x' + level.easy.positions.length
        context.fillStyle = level.levelUpColor
        context.fillText('NEXT LEVEL!', e.x, e.y + fontSize)
        const random = getRandom(mechanic.hits)
        addLevelPosition(random)
    }
}

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

Добавляем новую позицию в цепочку для отличника
function addLevelPosition(random){
    const lastPosition = level.easy.positions[level.easy.positions.length-1]
    const directions = []
    if(lastPosition[0]>level.easy.min[0]){ directions.push( [-1,0]) }
    if(lastPosition[0]<level.easy.max[0]){ directions.push( [1,0]) }
    if(lastPosition[1]>level.easy.min[1]){ directions.push( [0,-1]) }
    if(lastPosition[1]<level.easy.max[1]){ directions.push( [0,1]) }
    const directionId = Math.round(random * (directions.length-1))
    const direction = directions[directionId]
    const newX = lastPosition[0]+direction[0]*level.easy.step[0]
    const newY = lastPosition[1]+direction[1]*level.easy.step[1]
    const newPosition = [newX,newY]
    level.easy.positions.push(newPosition)
}

Детали

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

function getCursorPositionOnCanvas(canvas, evt) {
    var rect = canvas.getBoundingClientRect()
    return {
        x: evt.clientX - rect.left,
        y: evt.clientY - rect.top
    }
}

В качестве случайного значения (random) - я беру номер нажатия и рассчитываю от него косинус. Получается псевдослучайное (непредсказуемое) значение от -1 до 1, минус - убираем.

function getRandom(increment){
    const random = Math.abs(Math.cos(increment))
    return random
}

В игре используется 3 типа событий: игрок запустил игру - рисуем базу. Игрок нажал на документ - обрабатываем нажатие. Запускаем 2 таймера, первый - закраска экрана для отличника (winner), и для геометрического уменьшения размера попадания со временем, чтобы он не становился слишком большим. Регистрируем событие нажатия на экран. Событием будет нажатие указателем (pointwerdown) на тело документа. Следствие события (символ ⇒) будет меняться в зависимости от того, куда игрок попал.

События
drawBase()
document.body.addEventListener('pointerdown', onClick)
setInterval(()=>{
    if(mechanic.winner>0){
        fade()
    }
}, 1000/30)
setInterval(()=>{
    mechanic.size *= mechanic.pointerShrink
},100)

Полировка

После того, как механики готовы - можно приступать к "полировке" игры. Процесс разработки - бесконечен. Всегда есть что улучшить, появляются новые инструменты, новые возможности игровых систем, новые знания и навыки. Для создания и запуска игры из статьи - нужен только браузер и блокнот. Запустить можно в браузере, а это ПО есть в подавляющем числе пользовательских систем.

OSU
OSU

Однако, если есть желание и умение - даже игру с готовой механикой можно улучшить усилением эмоционального отклика (как в примере с добавлением звука). Это может быть как и графическое улучшение, так и звуковое. Можно усовершенствовать или добавить новые механики. Заменить прямоугольники на изображения, добавить фоновую музыку, добавить элементы управления и подсчета очков; мультиплеерное взаимодействие (multi - несколько, player - игрок), оптимизировать загрузку звуков и т.д. Один из успешных примеров кликера - OSU, немаловажной механикой в ней является музыкальный ритм, воздействие на чувства такта (tactus - прикосновение, толчокудар), эмоция когда "музыка качает".

Бесконечность - не предел
Бесконечность - не предел

Помимо игрового, у игры может быть как графический дизайн, так и звуковой. Каждый из этих компонент игры можно улучшить, однако это требует определенных навыков в этой области. В каждой игре есть свои наиболее значимые части, сильные и слабые стороны. Проблемы и их решения. Как и причины, по которым в них будут играть. Игра - может быть предметом искусства, сочетающая в себе огромное множество других предметов искусств: живописи, музыки, песнь, поэзии и прозы, инженерного мастерства, кино и т.д. Так же, как и множество новых способов взаимодействия с чувствами игрока, например тактильные (вибромотор, лазерный пистолет, контроллер и т.д.) или пространственные (очки виртуальной реальности).

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

Редактор кода Visual Studio Code https://code.visualstudio.com/

Онлайн генератор музыки Online Sequencer https://onlinesequencer.net/

Стандартный 2D контекст сильно ограничен и не производителен, поэтому я не рекомендую использовать его в профессиональной разработке игр. С появлением WebGL - игры в браузере могут быть намного более производительными, а значит - более наворочены графически. Я его в статье не использовал, т.к. он довольно сложный. Однако, его можно использовать так:

const canvas = document.getElementById("myCanvas");
const gl = canvas.getContext("webgl");

Есть две популярные библиотеки для работы в webgl, которые упрощают работу:

https://threejs.org/ для 3D

https://pixijs.com/ для 2D

Фидбэк

Обратный отклик необычайно важен в разработке игр. Это отдельная большая тема маркетинга, QA, самой разработки. Даже если фидбэк (feed - подавать, back - назад) - это мат наполовину, он может быть намного важнее, чем простое "Клевая игра, мне понравилось". Да, чувство признания - это механика игры жизни, но фидбэк в разработке не для этого.

В маркетинге в качестве фидбэка даже собирают действия пользователя. Когда игрок запустил игру, сколько уровней смог пройти, как быстро прошел до конца. Собрать статистику и на основе анализа этих данных - принимать важные решения, которые сделают игру многократно лучше.

Обратный отклик №1

На основе обратного отклика - игра впоследствии может еще неоднократно полироваться. Я дождался первого комментария от @Zara6502 и доработал статью и саму игру. Что я понял из обратной связи:

  • Прямоугольник для "отличника" слишком быстро пропадает. Поэтому сделал его перманентным.

  • Несколько одинаковых серых прямоугольников - была неоднозначность, стал закрашивать предыдущий зеленым при успехе.

  • Чтобы улучшить понимание механики прогресса - перманентно вывожу количество очков на экран.

Как я и написал выше - это процесс бесконечный. Важно, чтобы негативный фидбэк вызывал синее чувство, а не красное. Ведь наша жизнь - тоже своего рода игра. Фиксы по этому фидбэку внес в игру.

Обратный отклик №2

  • На мобильных устройствах всплыла проблема адаптивности. Элементы не помещаются в экран. Это решается адаптивным холстом с фиксированным расширением. Проблема предвидимая, решается тестированием.

  • Игроку не понятно, когда появляются новые "квадраты". Это происходит при +11 и выше очков. Механика скрытая, а должна быть явная, т.к. игрок не понимает условие награды.

  • Подсказали крутую и оригинальную идею по изменению механики. Вполне вероятно - попробую, но это уже совсем другая история ;)

QA

  • Почему способ простейший? Потому, как я не знаю более простого способа. Самый популярный язык (т.е. самый простой, т.к. изучать новый язык - сложно). Минимальные требования к среде разработки. Отсутствие дополнительных инструментов - которые тоже нужно изучать.

  • Но скачать ассетов в UE и натыкать скрипты мышкой же проще? Возможно, но, статья про то, как написать игру. Предполагаю, что читатель писать уже умеет.

  • Где попробовать? Выложил на itch.io. Максимум набрал 8 очков.

Комментарии (9)


  1. Zara6502
    06.07.2023 04:37
    +4

    Статью читал бегло, много воды, не нашел явных правил игры (или слепой), запустил игру, стал кликать по экрану, какие-то квадратики появлялись, какие-то пропадали, процесс был бесконечный (в разумных пределах конечно), потом стал кликать в черный квадрат, следил за изменением цвета, после четвертого квадрата всё окрасилось белым.

    Я считаю что такое в принципе не должно существовать, так как это безумное утрирование игрового процесса как такового. Можно было после первого же клика сделать геймовер и условно назвать игрой.

    Я много играл еще с 80-х и в конечном итоге пришёл к тому, что для меня самым важным стала реиграбельность, остальное сильно вторично. Как пример качественной игры - Death Stranding, но с нулевой реиграбельностью (этим в целом страдают все интерактивные полуигры-полукино), Кодзима сильон недотянул с песочницей, которая доступна в конце игры.

    В вашу игру не нужно играть изначально.

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


    1. ildarin Автор
      06.07.2023 04:37

      Спасибо за развернутую критику!

      Статья в основе своей - рефлексия на тему игр. А получившаяся игра - концептуальное решение исходя из этой рефлексии. Я изначально не знал, что в итоге получится. Я просто шел от вопроса: зачем нужна игра? Случайно ткнул пальцем в небо - научить игрока нажимать на серый квадрат. Затем - научить делать это в разных точках. Затем - делать это быстро.

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

      Саму игру я не в состоянии объективно оценить, т.к. всякая оценка субъективна, а у меня глаз замылен, тут я вынужден полагаться на мнение игроков. Получение фидбека - это вообще тема отдельной статьи, в основном в области маркетинга.

      потом стал кликать в черный квадрат, следил за изменением цвета, после четвертого квадрата всё окрасилось белым.

      Потом нужно нажать на серый квадрат. Но он быстро исчезает, Вы не успели это заметить, т.е. понять правила игры (механику) за 200мс. Значит - это моя ошибка, ошибка геймдизайна. Ну и ошибка в том, что серых квадратов было болше, чем один. Да, тоже ошибка при которой игрок не понял механику.

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

      Тут да, нужно создание базы перенести ближе к реализации.


      1. HcNetp
        06.07.2023 04:37

        Так-то интересно, можно подумать в этом ключе


      1. Zara6502
        06.07.2023 04:37

        Я просто шел от вопроса: зачем нужна игра?

        Не полезу в википедию за определением, но я игру воспринимаю как формат обучения, то есть получения опыта, через получение удовольствия от игры (без обучения тоже смысл понятен). Поэтому я очень положительно отношусь к играм, которые не просто клико*рочеры (ну или таймкиллеры).

        Случайно ткнул пальцем в небо - научить игрока нажимать на серый квадрат

        Давно, в 1993 году, я снимал комнату у пенсионеров, хозяйка дома очень любила играть в карты в "Дурака", но безумно не любила проигрывать. Когда в итоге я спросил - почему, ведь проигрыш это стимул становиться лучше, а регулярный выигрыш обесценивает победу - она ничего не поняла, но дала понять, что выигрывать нужно всегда и это хорошо. И тогда, утрируя, я ей предложил игру - взять мячик, в условие победы записать факт падения мача на землю, подкинуть, дождаться его падения, выиграть.

        Вот у вас примерно такой же подход к игровому процессу в данном случае.

        Например модификация вашей игры вот в таком ключе - серые квадратики появляются и исчезают то там то сям, ваша задача в них кликать, сначала процесс простой и медленный, потом квадраты появляются и исчезают быстрее попутно уменьшаясь в размерах. Игра заканчивается после 10 промахов. Так же каждый новый квадрат расширяет зону своего появления от центра, что вынуждает нас активно перемещать мышку. Игра на ловкость. Как поощрение каждые 10 кликнутых квадратов дают замедление на 5 итерацией например, можно выводить цветные бонусные квадраты разного цвета с разным эффектом. В конце показывать таблицу рекордов. Для обучения можно первые 10 квадратов выводить с надписью "click me".

        Исходил из теорий бихевиоризма. Так как я немного гуманитарий - возможно, я переоценил Ваши знания в этой теме

        А я полный гуманитарий, но читая заголовок "Простейший способ написать игру", внезапно, хочу прочитать про простейший способ написать игру. И вы, вероятно, плохо знакомы с бихевиоризмом, ну или так же утрировали основные принципы.

        И рассматривал игру как абстрактный процесс обучение, а не нечто конкретно-описательное

        Так это "простейший способ написать игру" или способ изучить поведение?

        Да, тоже ошибка при которой игрок не понял механику

        Есть очень хорошая игра "здесь должно быть название, но я не смог вспомнить", которая, на мой взгляд, провалилась именно из-за ошибки автора, так как весь интернет гудел в попытках понять что же нужно делать в этих чертовых загадках, причем сложность загадок никак не определялась в самом начале и не было "вводных" загадок, описывающих механики игры.


        1. ildarin Автор
          06.07.2023 04:37

          И вы, вероятно, плохо знакомы с бихевиоризмом, ну или так же утрировали основные принципы.

          Раскройте, пожалуйста, в чем утрирование?


          1. Zara6502
            06.07.2023 04:37
            +1

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

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


            1. ildarin Автор
              06.07.2023 04:37

              Ваша игра вызывала сильнейший стресс и дискомфорт

              ???? Надеюсь, Вы не затребуете от меня компенсацию за психологическую травму. Впервые слышу о человеке, который может заработатьПТСР от игры в кликер ????.

              Но если Вы серьезно и не шутите - советую обратиться к психологу.


              1. Zara6502
                06.07.2023 04:37
                +1

                Ну будем объективны - игры у вас нет, так как нет правил, нет цели, нет награды.

                Отправлять к психологу тех кто чем-то недоволен - это попахивает американщиной. Я вам рассказал о моем опыте взаимодействия с этой поделкой (не игра это).Опыт негативный. Всё.

                Я вообще не понимаю, что Вы подразумеваете под словом "утрирование"?

                очевидно - утрирование. Искаженная информация с выпячиванием какой-либо её части.

                Я думаю я и так много времени уделил этому материалу.


            1. ildarin Автор
              06.07.2023 04:37

              И вы, вероятно, плохо знакомы с бихевиоризмом, ну или так же утрировали основные принципы.

              Раскройте, пожалуйста, в чем утрирование?

              нет побуждающей награды, но это следствие

              Эм, утрирование в игре или в статье? Я вообще не понимаю, что Вы подразумеваете под словом "утрирование"? Как может быть отсутствие побуждающей награды - утрированием основных принципов бихевиоризма? О каких принципах идет речь?