Adjusting an event sprite script to work for single characters

erikmidnatt

Mercenary Wizard possessed by an Evil Spirit
Veteran
Joined
Oct 8, 2015
Messages
361
Reaction score
89
First Language
English
Primarily Uses
RMMV
So I'm working with the lovely MBS_FPLE plugin for MV and it has the ability to show sprite events in a first person dungeon crawler. However it only works with the sheets designed for 8 characters. I've spent several hours myself tinkering with the script, it seems like it would be relatively straight forward for those more familiar with math and all that ^_^. 


The goal: Modify this to work with the simple 3 X 4 single character sprite sheet. sprite.cellIndex should end up being between 0 and 11 after all the math is done!


I could potentially live without the directional portion of this (and normally took it out when I was experimenting),  Thanks for reading.


MBS.FPLE.Map.prototype._updateEvents = function(scene) {
this._events.forEach(function (sprite) {
var event = sprite._event;

var charIndex = event.characterIndex();
var row = 48;
var col = 3;
var offset = row * Math.floor(charIndex / 4) + (charIndex % 4) * col;

var direction;
if (!ImageManager.isObjectCharacter(event.characterName())) {
var eventAngle = ([0, 90, 270, 180])[event._direction / 2 - 1];
var playerAngle = $gamePlayer.cameraAngle();
var relativeAngle = playerAngle - eventAngle;

relativeAngle %= 360;
while (relativeAngle < 0)
relativeAngle += 360;

var relativeDirection = [180, 90, 270, 0].indexOf(relativeAngle) * 2 + 2;
direction = (relativeDirection / 2 - 1) % 4 * col * 4;
} else {
direction = (event._direction / 2 - 1) % 4 * col * 4;
}

sprite.position = new BABYLON.Vector3(-event._realX, MBS.FPLE.cameraHeight, event._realY);
sprite.cellIndex = offset + direction + ([0, 1, 2, 1])[event._pattern % 4];
});


Why not just use full sheets that have lots of empty space?


If I were to use 512pix assets that would result in a sheet over 6000 pixels wide!. So that would be a bad idea.
 
Last edited by a moderator:

Shaz

Veteran
Veteran
Joined
Mar 2, 2012
Messages
38,343
Reaction score
11,939
First Language
English
Primarily Uses
RMMV
Look at how Sprite_Character does it.
 

Doktor_Q

I'm not a real doktor, but I am a real Q
Veteran
Joined
Aug 1, 2016
Messages
653
Reaction score
381
First Language
English
Primarily Uses
RMMV
From looking over the code this afternoon, and reading Babylon's library, there's actually two functions that need work- that one, updateEvents, and also applyEvents, which creates them:


MBS.FPLE.Map.prototype._applyEvents = function(scene) {
this._events = [];
this._managers = {};

$gameMap.events().forEach(function (event) {
var charName = event.characterName();
if (!charName) return;

var manager;
if (!this._managers[charName]) {
manager = new BABYLON.SpriteManager(
"ev_" + charName,
"img/characters/" + encodeURIComponent(charName) + ".png",
256,
48,
scene
);
this._managers[charName] = manager;
} else {
manager = this._managers[charName];
}

var sprite = new BABYLON.Sprite("event" + event.id, manager);
sprite._event = event;
this._events.push(sprite);
}.bind(this));
};


There's really only two problems that I see: First the hard-coded "48" value in applyEvents is especially important, because that sets the size of image the babylon sprite object shows at any given time, the size of one frame, and assumes equal width and height. The solution is to have a way (probably the same way Sprite_Character does, as Shaz suggested) to tell how large your individual frame is, per image, store it on that image, and use it in place of the 48. This logic is also where you'd account for the $ flag on sprites, for your 1-character sheets, and any other modifiers on frame size.


The second problem shows up in the updateSprites function, where it assumes a fixed number of sprites per row: 12 (4 characters with 3 frames each). 12 frames per row, with four directions per character, that makes 48 frames for the actors in the top row, and 48 for the bottom, which is what the other hard-coded "48" is for, so it'll have to know how many frames are in the sheet here as well (more reason to store it on load). This is where it does the weird math with Direction, too.


Babel stores the spritesheet as a single, long film strip: c1 down, c2 down, c3 down, c4 down, followed by c1 left, c2 left, etc, all the way along. This makes it a little funky to deal with, since you have to jump over a bunch of pieces of one sprite to get to the rest of your same.


Code time!
 

First, this bit of code (comments mine):



var row = 48; // the number of frames it has to skip to reach the lower characters- 3 frames * 4 characters * 4 directions
var col = 3; // the number of frames it has to skip to get to a new character on the same row- 3 stepping frames
var offset = row * Math.floor(charIndex / 4) + (charIndex % 4) * col; // 4 is how many different characters are on a row


Assuming we separately store characters wide, frames per character, and directions, we could rewrite it as:



//assuming dirs = # of directions, frames = # of frames, and chRows = # of characters per row:
var row = frames*dirs*chRows;
var col = frames;
var offset = row * Math.floor(charIndex / chRows) + (charIndex % chRows) * col;


That change should get you onto the right character within the sheet, at least, but we still have to deal with the direction- you can't not deal with it very well, given how it's laid out. Commented original:



direction = (relativeDirection / 2 - 1) % 4 * col * 4; // % 4 is number of directions, the * 4 is number of characters per row
//the (direction / 2 - 1) seems to be converting from an internal 8-directional system (1-8) to a 0-3 4-direction system. It's fine.

/* some other code */

sprite.cellIndex = offset + direction + ([0, 1, 2, 1])[event._pattern % 4]; // this puts the pieces together
/* the 0, 1, 2, 1 might be familiar as the walk cycle. That's what it's calculating, here, the %4 is because the cycle is 4 frames,
* even if the last frame is a repeat of the 2nd. */


And with our updates, it becomes more like...



//assuming dirs = # of directions, frames = # of frames, and chRows = # of characters per row:
direction = (relativeDirection / 2 - 1) % dirs * col * chRow; // using more than 4 directions involves messy changes to math
//remember to update both direction = ... lines, and don't change anything they do differently!

/* some other code */

sprite.cellIndex = offset + direction + ([0, 1, 2, 1])[event._pattern % 4]; // We're leaving # of frames alone, or it's super messy



Fair warning, I haven't tested this yet, so there's probably something missing. I'll be trying to implement it myself over the weekend, so I'll post the detailed changes in the thread if I can get it working.
 

erikmidnatt

Mercenary Wizard possessed by an Evil Spirit
Veteran
Joined
Oct 8, 2015
Messages
361
Reaction score
89
First Language
English
Primarily Uses
RMMV
@Doktor_Q thanks for the suggestion, i never saw this reply until now for some reason T_T
 

Users Who Are Viewing This Thread (Users: 0, Guests: 1)

Latest Threads

Latest Posts

Latest Profile Posts

Can't wait for the next Sonichu
Birdhouses are usually made of wood. Birds typically live in trees. Trees are wood. Birdhouses are made of birdhouses.
He just discovered cellphones...

(I don't know why am I drawing so much these days...)
In medieval times, a common way to eat food was upon edible plates, which were made of bread, called trenchers.

Forum statistics

Threads
93,668
Messages
914,416
Members
123,254
Latest member
Ragnamano
Top