#javascript #colors #sprite #p5.js
#javascript #Цвет #sprite #p5.js
Вопрос:
Мы с моим другом решили вместе создать платформер в качестве нашего проекта по информатике. В настоящее время я использую функцию изображения в p5.js библиотека для переключения между изображениями и создания анимации для ходьбы, прыжков и т.д. Я посмотрел, как это делалось раньше для 2d-игр на таких системах, как Sega Mega Drive и NES, и понял, что в то время практически все, что использовалось для графики в 2D-пространстве, были спрайты.
После дополнительных исследований я выяснил, что спрайты были преобразованы в большой файл изображения с множеством различных анимаций кадров, а системы, подобные NES, были способны даже переворачивать эти части изображений назад и вверх ногами! Я даже читал, что вы можете перекрасить один и тот же спрайт в другую цветовую палитру!
Я посмотрел с p5.js в библиотеке есть возможности создания спрайтов, но когда я смотрю, как они работают, они всегда используются только для создания цветных квадратов, не показывая, как их использовать с файлами изображений, которые будут хранить в нем все изображения.
Мои вопросы таковы:
- Обладают ли спрайты по определению возможностями для выполнения всех действий, таких как изменение цветовой палитры спрайта, переворачивание его назад или вверх ногами и т.д.?
- Есть ли какое-либо преимущество в использовании спрайтов в отличие от использования функций отображения изображений и простого использования png?
- Почему они так широко использовались на старом оборудовании и используются ли они все еще сегодня в современных играх в стиле ретро (Showelknight, Dead Cells и т.д.)?
Ответ №1:
Чтобы кратко ответить на ваш вопрос о спрайтовых листах (также известных как текстурные атласы):
-
Обладают ли спрайты по определению возможностями для выполнения всех действий, таких как изменение цветовой палитры спрайта, переворачивание его назад или вверх ногами и т.д.?
Нет, вам все равно пришлось бы вручную программировать это. (В NES были вспомогательные инструкции, p5.js в настоящее время в p5.Image AFAIK нет функций flip / rotate90 градусов, однако вы могли бы «обмануть» и использовать буфер PGraphics для использования преобразований (
translate()/rotate()/scale()
для достижения перелистывания и поворота) -
Есть ли какое-либо преимущество в использовании спрайтов в отличие от использования функций отображения изображений и простого использования png?
Вы бы выделили память для листа спрайтов один раз, а затем просто ссылались бы на те области, которые позже, поскольку фреймы необходимо скопировать (в отличие от множества независимых изображений в массивах, многократно загружающих / декодирующих ресурс). Благодаря большему количеству кадров на персонажа / игровой объект и большему количеству игровых объектов, способных эффективно упаковывать пиксели, действительно экономится оперативная память, что позволяет использовать его для более увлекательной игровой механики и эффектов, а не просто для необработанных ресурсов.
-
Почему они так широко использовались на старом оборудовании и используются ли они все еще сегодня в современных играх в стиле ретро (Showelknight, Dead Cells и т.д.)?
Тогда это было ограничение аппаратного обеспечения, поэтому было важно максимально экономить ресурсы, чтобы иметь возможность захватить аудиторию жестким управлением / игровой механикой и сюжетом. Они все еще используются сегодня для 3D-видеоигр и графики в реальном времени: для GPU требовалась мощность 2 текстур. Несмотря на то, что это практически одно и то же, даже современные игры по-прежнему содержат 2D-текстуры, которые применяются к 3D-моделям.
Помимо видеоигр, таблицы спрайтов нашли еще одно применение в Интернете. Прямо перед нами пример — таблица спрайтов StackExchange favicon Причина в этом похожа, но отличается:
- похоже, потому что это все еще оптимизация
- отличается тем, что мы можем легко загружать каждый отдельный значок, что означало бы выполнение нескольких отдельных HTTP-запросов для каждого отдельного (инициализация соединения, ожидание подтверждения от сервера, получение данных, кэширование данных).
Эффективнее выполнить один запрос и легко использовать CSS для отображения разделов одного изображения для нужного значка.
Обратите внимание, что электронную таблицу можно было бы оптимизировать еще больше, поскольку мета-иконки представляют собой версию основных сайтов в оттенках серого, а также есть CSS-фильтр в оттенках серого, однако это может немного усложнить чтение и управление общей базой кода и обеспечить гибкость использования мета-иконки, которая не обязательно является копией оригинала в оттенках серого. Это иллюстрирует тот факт, что они оптимизируют количество запросов, не обязательно размер файла и распределение памяти.
Для вашей собственной игры вам предстоит найти этот тонкий баланс между тем, чтобы максимально оптимизировать ее, и тем, чтобы ваша кодовая база была максимально гибкой.
Назад к p5.js это было бы вопросом использования 2 изображений: загруженного листа спрайта и отдельного меньшего изображения, выделенного для копирования() пикселей спрайта.
Вот очень простой пример отображения нескольких кадров спрайта Mario:
В качестве ссылки здесь также приведен код:
Вы можете запустить его ниже:
// full spritesheet
var spriteSheet;
// a sprite sampling from sprite sheet
var mario;
// 8 frames in the spritesheet
var numSprites = 8;
// each sprite in the sheet has this bounding box
var spriteWidth = 18;
var spriteHeight = 24;
// start frame
var spriteIndex = 1;
function setup(){
createCanvas(150,150);
frameRate(24);
noSmooth();
noFill();
spriteSheet = loadImage("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJAAAAAYCAYAAAAVpXQNAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8 IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQwIDc5LjE2MDQ1MSwgMjAxNy8wNS8wNi0wMTowODoyMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTggKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MzE1ODI1MkNDQ0MzMTFFOEJFNjA5ODI5Q0U0NzlGOEEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MzE1ODI1MkRDQ0MzMTFFOEJFNjA5ODI5Q0U0NzlGOEEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpFM0U1NkY3RkNDQTMxMUU4QkU2MDk4MjlDRTQ3OUY4QSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpFM0U1NkY4MENDQTMxMUU4QkU2MDk4MjlDRTQ3OUY4QSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PszND6MAAAXWSURBVHja7JstkKMwFIDDDgK5srISWVlZWVmJRFbiDrecQyIrK5HIypWVlcjKlStxXF5IaAj5IZDe7d5sZhjKFr6 /4QH67Vti36Gfni/f1udn9cnYtQ0PHqwb9/e/lvb N/JYYcsG0V7lWUef8yc5YIxZ0DwJOd7dxCvWxZEpkB0odsc/ZawgOMvddoUYZY6jV1f7pLHH094OyIU4e9E1rMYVsGDB/mMgwihN /ZcrnUz4blf3WnAYNdf/n4JPswrdEabfEfcoSCAv0NxpQsveItKgNUNs3ka13I5VI/W5b/lZ0GjDiMB4xDfcZZzdxFGeBERTC6YFgnR9AFURGvyTro1xPlcqnfHNbLVEgYX1EQFijAxqkYxFKQJQy4niijGhKWC4YuOWADLmz3 Np9CckBpsbBcy0/nqaba/3msnwTRDsA8jac32cxdBkmXN8kx9E5wetKn1kOGLZZWkHwmDJeYhuQLShOzDZGmfZljILNbnT9YD9Rtzks/xkCLWXwTmpu7z2LOD6OyDH7O xR9f4UxpQstU0OnjEIaCxTf0w/BxqZSBXEchd59NCDcSAAuX2eR4O2gkvWiwoyUozbw90G63XoBJnDEAORZ/FGFu9 VCwXDJHHl3dWzfh9hQPkYKggwOkHCxga5Hzyace5HFZRWrl629N9kpZk0 o3k WbIJANMkhn9Wh8izqDocqMEYtWi0XyzGFYZmn9EaHtZtWt8wxBrQsWsSE5mnZpNe8rF9Wll81izGX5rgVywSC399hhhxrNZrlgTMlS2 SoZgb1iEP1IzJwFbCvYmwdNZxSPZ2tbFm/ ABaAnGtFFsnVHiaYCyYEiBrxRKrkscF4ykZj/kBlm0Jp5 KolV3x/dR0cYlZ3NRN0XwLGX5oy wcksE4hnJ6kCyzZrBDNs05JYfWFus4KPLu0apeIusYLlguEwO0q2mjUa41Z/CAR3Ejjbf8QZOgqfNAj0qW451PdUJuh8a4x3YEpYvU/pKs7fYVLMEgnPD235wvS1jfzv1xiNKCY8IwtsR7VevKHovkKqj7YIxyFSapZdLg rNxTrBZI86OrnUnEbS1SbTGQ4onkV42PH7XUg 76IN6Syco/dWZ lLF93qzpHIH5AEIGDilWJLmE2mbGljtINcOAZV5DbBhp3zVMYYplnRganiwlikxziYBWf5xzDgvweVE/Z1AqOT4OgZcl6QZ oiLZdgKed//L7DdXXBIXbor3fUmVgsyBiPjOyOB1fVIaFDRzPIOl6032HIesqaE0dSsh UgFoZ1bK6PokrUwhcBJzlriHRwXQ5d3UV6TLrKUMVZmHz6QC4QSDxICtySoUlzutbXiZ OlCxoEgguBp6kTeRcbHOVu3YGczh8sGBI Sw8kGv2liGaew4ToBehSgcDx1gdgrxRsJDJMolIJHG7KOtlha9/mZyoJQCYpmJTI9snTB0E6ztDrbZHy37upkAIddDq/9dyInCFIio7Vc bmfNbAsnR9mcEQWyGVeA0mcfzFAnqUUMXB FoxP3N/5JtwaF I6Bgus7HDxbAKR2cWU8arkcDlAP1R3j1TWXDCibqlAZIGk7vU22OtefY448Ld3dCN74xpIB1ZBpErRTBcNPVUpmAp4ReB3 UUlPxWohonRL1TTtA3yXB9EXOUQdZqTHEkWoVM0dJiMY1zHYblooHqo hxMT8RPNzT5lVM4n6z36qHexFeZ/Nmer1tQEaXqzAiRK9Wdu56pFATZMVw9nIdZzbVp XVIGuqdbmL8k4zHxymuSmlZUPsErZj1hAN2OmDbszWLgdPbVnJXrWQoEoVfhrBK2u3Hz/Z8FxDnSkGjja5RZg8XjGdlPKczXMOCaMDRtAP6tzenTo2WUyjfHyO hPZCKK IHnupfvA6qum9GMUrra6G53mt7Ddhqhl0hiXTTv/e8ESGjCPq1NtmaiYL5/3PL9V7X/G/MnQverMAUK1Zprx4PpXxM75pAP2M7zP CDAA39ndLOWkvxoAAAAASUVORK5CYII=");
// create an image to draw a single sprite into
mario = createImage(spriteWidth,spriteHeight);
}
// set all pixels (R,G,B,A) to the same value (e.g. clear image with a colour)
function setAllPixels(image,brightness){
// prep. pixels for manipulation
image.loadPixels();
let numPixels = image.pixels.length;
// loop through all pixels (spriteWidth * spriteHeight * colourChannels(4))
for(let i = 0 ; i < numPixels; i ){
image.pixels[i] = brightness;
}
// commit value changes to image: updates it all in one go, more efficient than set()
image.updatePixels();
}
function draw(){
// clear frame
background(255);
// display the whole sprite sheet
image(spriteSheet,0,0);
// increment sprite index
spriteIndex ;
// reset sprite index if out of bounds
if(spriteIndex >= numSprites){
spriteIndex = 0;
}
// visualise sprite copy rect
rect(spriteIndex * spriteWidth,0,spriteWidth,spriteHeight);
// clear mario image
setAllPixels(mario,255);
// copy pixels from sprite sheet into sprite
// copy (source image, source coordinates(x,y,w,h), destination coordiantes (x,y,w,h) )
mario.copy(spriteSheet,
spriteIndex * spriteWidth,0,spriteWidth,spriteHeight,
0 ,0,spriteWidth,spriteHeight);
// display mario sprite
image(mario,mouseX,mouseY spriteHeight);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.min.js"></script>
Я использую строку в кодировке base64, чтобы избежать проблем с CORS, но вы должны иметь возможность использовать preload()
и loadImage()
свой собственный лист спрайтов.
Что касается игр для NES, я рекомендую вам ознакомиться с написанием игр для NES! С ассемблером!! и как мы помещаем игру для NES в 40 килобайт. Оба они являются впечатляющими техническими достижениями и отлично справляются с визуализацией листа спрайтов и ограничений палитры на платформе.
Вам не придется преодолевать эти препятствия и разбираться в двоичных файлах / байтах, чтобы иметь возможность использовать в p5.js как вы могли видеть ранее, но интересно понять эти старые ограничения для создания эффективных игр.
С точки зрения программного обеспечения, существует множество вариантов. Даже если я не одобряю, я могу порекомендовать Texture Packer. Есть простая версия веб-приложения, которую вы можете попробовать онлайн прямо сейчас: SpriteSheetPacker, и у них есть пара глупых рекламных анимаций: Таблицы спрайтов — Часть 1 фильма и Таблицы спрайтов — Часть 2 фильма — Производительность
Во времена actionscript существовала пара действительно хороших игровых движков, ориентированных на пиксели: Flixel (использовался для оригинального Canabalt) и FlashPunk. Доступны порты HaXe: такие как HaxeFlixel и HaxePunk, а также другие собственные JS (например, PixelJS, phaser, ImpactJS и т.д.).
Недавно было интересно посмотреть игры в стиле PixelArt, использующие 2D движки WebGL, такие как PixiJS. Хотя игра очень коммерческая и простая с точки зрения игровой механики, вот прекрасно отрисованная игра от Stink Digital Studios: Miu Miu Twist
p5.js отлично подходит для полного понимания некоторых базовых понятий, которые имеют решающее значение с точки зрения загрузки / обработки ресурсов, работы с пикселями, обработки ввода и т.д. поскольку библиотека имеет довольно широкий охват, она может быть оптимизирована только для игр. Отличное начало!
Комментарии:
1. Здравствуйте, большое вам спасибо за вашу помощь. Ваши исходники были действительно полезны, надеюсь, теперь я смогу разобраться в этом сам. Не ожидал получить помощь непосредственно с библиотекой p5js, но, полагаю, она более популярна, чем я думал. Надеюсь, у вас хороший день!