Improved handling for where to put character on screen if layer is not given.

Punch position uses the actual easing from utage now.
Fix audio context not being able to be created without user input in some new browsers.
Some changes for diva fades.
Made ui image match games slightly more.
Disabled select on text since you can't select it without triggering next anyways.
Various other minor fixes.
这个提交包含在:
fire bingo 2018-05-04 09:33:14 -07:00
父节点 6a4bb7a459
当前提交 3b91e57a1c
共有 6 个文件被更改,包括 219 次插入94 次删除

查看文件

@ -64,9 +64,9 @@
#text-container { position: absolute; margin: auto; height: 750px; width: 1334px; font-family: 'FOT-RodinNTLGPro'; }
#text-container #title { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; font-size: 20px; transition: opacity 0.3s; }
#text-container #title { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; font-size: 20px; transition: opacity 0.3s; cursor: default; user-select: none; }
#text-container #diva { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; font-size: 34px; transition: opacity 0.3s; }
#text-container #diva { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; font-size: 34px; transition: opacity 0.3s; cursor: default; user-select: none; }
#text-container #dialog-box { box-sizing: border-box; position: absolute; bottom: 0; text-align: left; width: 100%; height: 200px; }
@ -74,11 +74,11 @@
#dialog-box { color: white; font-weight: bold; text-shadow: 1px 1px 6px black; transition: opacity 0.1s; }
#dialog-box #character { position: absolute; top: -5px; left: 70px; font-size: 30px; }
#dialog-box #character { position: absolute; top: -5px; left: 70px; font-size: 30px; cursor: default; user-select: none; }
#dialog-box #dialog { overflow: hidden; position: absolute; padding: 0 30px 0 70px; margin-top: 60px; box-sizing: border-box; height: 120px; width: 100%; font-size: 28px; font-weight: normal; line-height: 68px; }
#dialog #dialog-inner { max-width: 1125px; }
#dialog #dialog-inner { max-width: 1125px; cursor: default; user-select: none; }
#dialog b { font-weight: bold; }

二进制文件未显示。

之前

宽度:  |  高度:  |  大小: 590 KiB

之后

宽度:  |  高度:  |  大小: 608 KiB

查看文件

@ -92,14 +92,24 @@ class commonFunctions {
t = -0.45;
}
break;
case "punch": {
if (t === 0 || t === 1)
return start;
debugger;
let change = end - start;
let num = 0.3;
let rad = Math.PI * 2;
let num2 = num / rad * Math.asin(0);
return change * Math.pow(2, -10 * t) * Math.sin((t * 1 - num2) * rad / num);
}
//http://www.gizma.com/easing/
case "quadinout":
var change = end - start;
case "quadinout": {
let change = end - start;
t = t * 2;
if (t < 1) { return change/2*t*t + start; }
t--;
return -change/2 * (t*(t-2) - 1) + start;
break;
}
}
return (1 - t) * start + t * end;
//-(2*x-1)^4 +1
@ -118,10 +128,9 @@ class commonFunctions {
static hexToRgb (hex) {
hex = hex.toString(16);
let bigint = parseInt(hex, 16);
let r = (bigint >> 16) & 255;
let g = (bigint >> 8) & 255;
let b = bigint & 255;
let r = (hex >> 16) & 255;
let g = (hex >> 8) & 255;
let b = hex & 255;
return [r, g, b];
}

查看文件

@ -7,9 +7,8 @@ const pixiApp = {
const utage = new UtageInfo();
const textFunc = new TextFunctions();
const audio = new audioController(utage);
let audio = undefined; //Cant create a audio context without user input.
const player = new Player(pixiApp, utage, textFunc, audio);
const context = new (window.AudioContext || window.webkitAudioContext)();
const languages = ["eng", "jpn"];
let bodyLoaded = false;
let utageLoaded = false;
@ -72,12 +71,14 @@ function loadLocalStorage() {
//audio
volume = localStorage.getItem('volume') || 0.5;
volume = Number(volume);
audio.changeVolume(volume);
document.getElementById('volume-range').value = volume * 100;
isMuted = localStorage.getItem('ismuted') || false;
if(isMuted === "false") { isMuted = false; }
else if(isMuted === "true") { isMuted = true; }
audio.mute(isMuted);
if(audio) {
audio.changeVolume(volume);
audio.mute(isMuted);
}
if(isMuted) {
document.getElementById('mute-button').innerText = "🔇";
} else {
@ -160,29 +161,39 @@ function closeMissionModal(event, wasStarted) {
}
function missionChanged(value) {
let newMission = utage.availableMissions[value];
currentMission = newMission;
let promises = [
utage.parseMissionFile(`${utage.rootDirectory}XDUData/${newMission.Path.replace('Asset/', '').replace('.utage', '').replace('.tsv', '_t.tsv')}`),
utage.loadMissionTranslation(`${utage.rootDirectory}XDUData/${newMission.Path.replace('Asset/', '').replace('.utage', '').replace('.tsv', `_translations_${selectedLang}.json`)}`, selectedLang),
player.resetAll()
];
closeMissionModal(undefined, true);
Promise.all(promises)
if(!audio) {
audio = new audioController(utage);
audio.changeVolume(volume);
audio.mute(isMuted);
player.audio = audio;
}
player.resetAll()
.then((success) => {
let res = player.playFile()
let newMission = utage.availableMissions[value];
currentMission = newMission;
let promises = [
utage.parseMissionFile(`${utage.rootDirectory}XDUData/${newMission.Path.replace('Asset/', '').replace('.utage', '').replace('.tsv', '_t.tsv')}`),
utage.loadMissionTranslation(`${utage.rootDirectory}XDUData/${newMission.Path.replace('Asset/', '').replace('.utage', '').replace('.tsv', `_translations_${selectedLang}.json`)}`, selectedLang)
];
closeMissionModal(undefined, true);
Promise.all(promises)
.then((success) => {
player.resetAll();
currentMission = undefined;
debugger;
let res = player.playFile()
.then((success) => {
player.resetAll();
currentMission = undefined;
debugger;
}, (failure) => {
debugger;
currentMission = undefined;
console.log(failure);
});
}, (failure) => {
debugger;
currentMission = undefined;
console.log(failure);
});
}, (failure) => {
currentMission = undefined;
console.log(failure);
});
}
@ -215,7 +226,9 @@ function dialogScrollDown(event) {
function toggleMute(event) {
isMuted = !isMuted;
audio.mute(isMuted);
if(audio) {
audio.mute(isMuted);
}
localStorage.setItem('ismuted', isMuted);
if(isMuted) {
document.getElementById('mute-button').innerText = "🔇";
@ -225,9 +238,11 @@ function toggleMute(event) {
}
function onVolumeChange(event) {
let vol = event.currentTarget.value / 100;
audio.changeVolume(vol);
localStorage.setItem('volume', vol);
volume = Number(event.currentTarget.value) / 100;
if(audio) {
audio.changeVolume(volume);
}
localStorage.setItem('volume', volume);
}
function onWindowResize(event) {

查看文件

@ -17,7 +17,6 @@ class Player {
this.titleWaitTime = 5;
this.currentCharacters = {};
this.lastCharOffLayer = undefined;
this.layers = {};
this.sprites = {};
this.currentCommand = undefined;
@ -134,6 +133,8 @@ class Player {
});
//Manually load white bg for fading. Can be tinted to change color.
this.loader.add('bg|whiteFade', `${this.utage.rootDirectory}Images/white.png`);
//this isint in the texture file.
this.loader.add('bg|titlecard', `${this.utage.rootDirectory}XDUData/Sample/Texture/BG/bg_title.jpg`)
this.loader
.on("progress", (loader, resource) => {
this.onPixiProgress(loader, resource);
@ -183,6 +184,7 @@ class Player {
}
}
//https://jsfiddle.net/60e5pp8d/1/
buildShaders() {
let divalefttorightfade = new PIXI.Filter(null, leftToRightFadeShader, {
time: { type: 'f', value: 0 },
@ -190,13 +192,22 @@ class Player {
fadeincolor: { type: 'v4', value: [0.0,0.0,0.0,1.0] },
fadeoutcolor: { type: 'v4', value: [0.0,0.0,0.0,0.0] }
});
divalefttorightfade.apply = function(filterManager, input, output)
{
divalefttorightfade.apply = baseShaderApply;
this.shaders['divalefttorightfade'] = divalefttorightfade;
let divarighttoleftfade = new PIXI.Filter(null, leftToRightFadeShader, {
time: { type: 'f', value: 0 },
dimensions: { type: 'v2', value: [baseDimensions.width, baseDimensions.height] },
fadeincolor: { type: 'v4', value: [0.0,0.0,0.0,1.0] },
fadeoutcolor: { type: 'v4', value: [0.0,0.0,0.0,0.0] }
});
divarighttoleftfade.apply = baseShaderApply;
this.shaders['divarighttoleftfade'] = divarighttoleftfade;
function baseShaderApply(filterManager, input, output) {
this.uniforms.dimensions[0] = input.sourceFrame.width
this.uniforms.dimensions[1] = input.sourceFrame.height
filterManager.applyFilter(this, input, output);
}
this.shaders['divalefttorightfade'] = divalefttorightfade;
}
//Laoding progress functions
@ -280,15 +291,17 @@ class Player {
if(pos >= 1) {
pos = 1;
toRemove.push(i);
var split = l.post.split('|');
switch(split[0].toLowerCase()) {
case "destroy":
l.object.destroy();
continue;
case "clearshader":
l.object.filters = null;
l.object.alpha = Number(split[1]);
break;
if(l.post) {
var split = l.post.split('|');
switch(split[0].toLowerCase()) {
case "destroy":
l.object.destroy();
continue;
case "clearshader":
l.object.filters = null;
l.object.alpha = Number(split[1]);
break;
}
}
}
switch(l.type) {
@ -358,6 +371,17 @@ class Player {
switch((cur.Command || "").toLowerCase()) {
case "scenetitle01": {
this.waitTime = this.titleWaitTime * 1000;
try {
let container = this.layers[this.bgLayerName].container;
let sprite = new PIXI.Sprite(this.loader.resources[`bg|titlecard`].texture);
container.visible = true;
sprite.scale.set(1.30273438, 1.30273438);
sprite.anchor.set(0.5, 0.5);
sprite.alpha = 0;
container.addChild(sprite);
this.lerpTargets.push({type: 'alpha', object: sprite, curTime: 0, time: 300, finalV: 1, initV: 0});
this.lerpTargets.push({type: 'alpha', object: sprite, curTime: -(this.waitTime+500), time: 300, finalV: 0, initV: 1, post: "destroy"});
} catch (error) { }
let text = cur.English ? (utage.currentTranslation[cur.English] || cur.Text) : cur.Text;
this.text.titleText(true, text);
break;
@ -383,41 +407,26 @@ class Player {
this.lerpTargets.push({type: 'alpha', object: this.layers["bg|whiteFade"].sprite, curTime: 0, time: this.waitTime, finalV: 0, initV: 1});
break;
case "divalefttorightblackfade": {
//This has a color but ive always seen it be black and its called black so im just assuming for now.
this.waitTime = Number(cur.Arg6) * 1000;
let sprite = this.layers["bg|whiteFade"].sprite;
let filter = this.shaders['divalefttorightfade'];
var color = commonFunctions.getColorFromName(cur.Arg1);
let rgbcolor = commonFunctions.hexToRgb(color);
sprite.tint = color;
sprite.alpha = 1.0;
filter.uniforms.time = 0.0;
filter.uniforms.fadeincolor = [rgbcolor[0],rgbcolor[1],rgbcolor[2],1.0];
filter.uniforms.fadeoutcolor = [0.0,0.0,0.0,0.0];
sprite.filters = [ filter ];
this.lerpTargets.push({type: 'shader', object: sprite, curTime: 0, time: this.waitTime, post: 'clearshader|1'});
this.processDivaFade(cur, false, false);
break;
}
case "divalefttorightclearfade": {
this.waitTime = Number(cur.Arg6) * 1000;
let sprite = this.layers["bg|whiteFade"].sprite
let filter = this.shaders['divalefttorightfade'];
var color = commonFunctions.getColorFromName(cur.Arg1);
let rgbcolor = commonFunctions.hexToRgb(color);
sprite.tint = color;
sprite.alpha = 1.0;
filter.uniforms.time = 0.0;
filter.uniforms.fadeincolor = [0.0,0.0,0.0,0.0];
filter.uniforms.fadeoutcolor = [rgbcolor[0],rgbcolor[1],rgbcolor[2],1.0];
sprite.filters = [ filter ];
this.lerpTargets.push({type: 'shader', object: sprite, curTime: 0, time: this.waitTime, post: 'clearshader|0'});
this.processDivaFade(cur, true, false);
break;
}
case "divarighttoleftblackfade": {
this.processDivaFade(cur, false, true);
break;
}
case "divarighttoleftclearfade": {
this.processDivaFade(cur, true, true);
break;
}
case "bg": {
let bgInfo = this.utage.textureInfo[cur.Arg1];
let container = this.layers[this.bgLayerName].container;
//If we have a fadetime we need to keep the old bg, fade its alpha out, then destroy it.
if(cur.Arg6) {
if(cur.Arg6 && container.children[0]) {
//I know im assuming a lot that there is already only one bg on the layer.
this.lerpTargets.push({type: 'alpha', object: container.children[0], curTime: 0, time: (Number(cur.Arg6) * 1000), finalV: 0, initV: 1, post: "destroy"});
} else {
@ -496,8 +505,7 @@ class Player {
let curChar = this.currentCharacters[c];
if(curChar.charName === cur.Arg1) {
let time = Number(cur.Arg6) * 1000;
if(!time) { time = 100; }
this.lastCharOffLayer = this.currentCharacters[c].layer;
if(!time) { time = 250; }
this.lerpTargets.push({type: 'alpha', object: curChar.sprite, curTime: 0, time: time, finalV: 0, initV: 1, post: "destroy" });
this.currentCharacters[c] = undefined;
break;
@ -508,6 +516,7 @@ class Player {
this.processTween(delta, cur);
break;
case "bgm":
this.audio.stopSound('bgm');
if(!this.utage.soundInfo[cur.Arg1]) {
break;
}
@ -540,6 +549,21 @@ class Player {
}
}
processDivaFade(command, clear, rtl) {
this.waitTime = Number(command.Arg6) * 1000;
let sprite = this.layers["bg|whiteFade"].sprite;
let filter = this.shaders[(rtl ? 'divarighttoleftblackfade' : 'divalefttorightfade')];
var color = commonFunctions.getColorFromName(command.Arg1);
let rgbcolor = commonFunctions.hexToRgb(color);
sprite.tint = color;
sprite.alpha = 1.0;
filter.uniforms.time = 0.0;
filter.uniforms.fadeincolor = (clear ? [0.0,0.0,0.0,0.0] : [rgbcolor[0],rgbcolor[1],rgbcolor[2],1.0]);
filter.uniforms.fadeoutcolor = (clear ? [rgbcolor[0],rgbcolor[1],rgbcolor[2],1.0] : [0.0,0.0,0.0,0.0]);
sprite.filters = [filter];
this.lerpTargets.push({type: 'shader', object: sprite, curTime: 0, time: this.waitTime, post: `clearshader|${(clear ? '0' : '1')}`});
}
//This should mostly be handling things like text
processCommandOther(delta) {
let cur = this.currentCommand;
@ -553,7 +577,8 @@ class Player {
checkPutCharacterScreen(cur, special = false) {
if((!cur.Command || special) && cur.Arg1 && this.utage.characterInfo[cur.Arg1]) {
let lay = undefined;
let curChar = undefined;
let curChar = undefined; //The character that is currently on screen with the same name as Arg1.
let prevChar = undefined; //The character that is already on the layer we are trying to put the new char on.
//First check if the character is already on screen
for(let c of Object.keys(this.currentCharacters)) {
if(!this.currentCharacters[c]) { continue; }
@ -574,23 +599,36 @@ class Player {
}
let chr = this.utage.characterInfo[cur.Arg1][cur.Arg2];
//If the script gives us a layer get that layer and if there is a character on it already.
if(cur.Arg3 && !curChar) {
if(cur.Arg3) {
lay = this.layers[cur.Arg3];
curChar = this.currentCharacters[cur.Arg3];
prevChar = this.currentCharacters[cur.Arg3];
if(!lay) { return; }
//If they didn't give us a layer try to use the last layer a character was removed from.
} else if(!curChar) {
lay = this.lastCharOffLayer;
//If they didn't give us a layer check for left and right positioning or try to go to default (middle)
} else if(!curChar && !lay) {
if(isCharOnLeft.apply(this)) {
lay = this.layers['キャラ右'];
} else if(isCharOnRight.apply(this)) {
lay = this.layers['キャラ左'];
} else {
lay = this.layers['キャラ中央'];
}
if(!lay) { return; }
cur.Arg3 = lay.info.LayerName;
prevChar = this.currentCharacters[cur.Arg3];
}
//If this chracter is already here and not changing patterns don't change anything.
if(curChar && curChar.charName === cur.Arg1 && curChar.character.Pattern === cur.Arg2) {
//If the character is already on screen on another layer move them to the new layer.
if(curChar && lay && curChar.layer.info.LayerName !== cur.Arg3) {
this.lerpTargets.push({type: 'alpha', object: curChar.sprite, curTime: 0, time: 200, finalV: 0, initV: 1, post: "destroy" });
this.currentCharacters[curChar.layer.info.LayerName] = undefined;
}
//If this character is already here and not changing patterns don't change anything.
else if(curChar && curChar.charName === cur.Arg1 && curChar.character.Pattern === cur.Arg2) {
return;
}
//If the layer already has a different character on it remove it.
if(curChar && (curChar.character.NameText !== chr.NameText || curChar.character.Pattern !== chr.Pattern)) {
this.lerpTargets.push({type: 'alpha', object: curChar.sprite, curTime: 0, time: 200, finalV: 0, initV: 1, post: "destroy" });
if(prevChar && (prevChar.character.NameText !== chr.NameText || prevChar.character.Pattern !== chr.Pattern)) {
this.lerpTargets.push({type: 'alpha', object: prevChar.sprite, curTime: 0, time: 200, finalV: 0, initV: 1, post: "destroy" });
this.currentCharacters[cur.Arg3] = undefined;
}
let sprite = new PIXI.Sprite(this.loader.resources[`char|${cur.Arg1}|${cur.Arg2}`].texture);
@ -599,6 +637,11 @@ class Player {
sprite.anchor.set(anchor.x, anchor.y);
sprite.alpha = 0;
let fadeTime = 200;
//If the character is already on screen put te new sprite in the same position as the old one.
if(curChar) {
sprite.position.x = curChar.sprite.position.x;
sprite.position.y = curChar.sprite.position.y;
}
if(cur.Arg4) {
sprite.position.x = Number(cur.Arg4);
}
@ -606,14 +649,44 @@ class Player {
sprite.position.y = Number(cur.Arg5);
}
if(cur.Arg6) {
//Im halving this because their fades take too fucking long and look bad.
//Im halving this because their fades take too fucking long and looks bad.
fadeTime = (Number(cur.Arg6) * 1000) / 2;
}
this.currentCharacters[cur.Arg3] = { layer: lay, character: chr, charName: cur.Arg1, sprite: sprite };
this.lerpTargets.push({type: 'alpha', object: sprite, curTime: 0, time: fadeTime, finalV: 1, initV: 0 });
if(fadeTime > 0) {
this.lerpTargets.push({type: 'alpha', object: sprite, curTime: 0, time: fadeTime, finalV: 1, initV: 0 });
} else {
sprite.alpha = 1;
}
lay.container.addChild(sprite);
lay.container.visible = true;
}
function isCharOnLeft() {
for(let l of Object.keys(this.layers)) {
let lay = this.layers[l].info;
if(!lay) { continue; }
if(lay.LayerName.includes('キャラ左')) {
if(this.currentCharacters[lay.LayerName]) {
return true;
}
}
}
return false;
}
function isCharOnRight() {
for(let l of Object.keys(this.layers)) {
let lay = this.layers[l].info;
if(!lay) { continue; }
if(lay.LayerName.includes('キャラ右')) {
if(this.currentCharacters[lay.LayerName]) {
return true;
}
}
}
return false;
}
}
//Checks if the current command is trying to put text on the screen.
@ -715,18 +788,16 @@ class Player {
case "punchposition": {
let props = commonFunctions.getPropertiesFromTweenCommand(cur.Arg3);
if(props.time == undefined) { props.time = 1000; }
//just watching these in game they definitely don't take as long as is advertised so i'm shortening it a bit.
props.time = props.time * 0.5;
if(!cur.Arg6 || cur.Arg6 !== "NoWait") {
this.waitTime = props.time + (props.delay || 0);
}
if(props.x != undefined) {
this.lerpTargets.push({type: 'position.x', object: curChar.sprite, curTime: 0 - (props.delay || 0), time: props.time,
finalV: curChar.sprite.position.x + props.x, initV: curChar.sprite.position.x, inter: 'dampsin' });
finalV: curChar.sprite.position.x + props.x, initV: curChar.sprite.position.x, inter: 'punch' });
}
if(props.y != undefined) {
this.lerpTargets.push({type: 'position.y', object: curChar.sprite, curTime: 0 - (props.delay || 0), time: props.time,
finalV: curChar.sprite.position.y + props.y, initV: curChar.sprite.position.y, inter: 'dampsin' });
finalV: curChar.sprite.position.y + props.y, initV: curChar.sprite.position.y, inter: 'punch' });
}
break;
}
@ -899,9 +970,9 @@ class Player {
PIXI.utils.TextureCache[tex].destroy(true);
}
}
utage.currentPlayingFile.length = 0;
this.loader.reset();
this.currentCharacters = {};
this.lastCharOffLayer = undefined;
this.layers = {};
this.sprites = {};
this.currentCommand = undefined;

查看文件

@ -1,3 +1,4 @@
//http://glslsandbox.com/e#39992.0
const leftToRightFadeShader = `
precision mediump float;
varying vec2 vTextureCoord;
@ -28,4 +29,33 @@ void main( void ) {
gl_FragColor = color;
}`
//http://glslsandbox.com/e#39992.0
const rightToLeftFadeShader = `
precision mediump float;
varying vec2 vTextureCoord;
uniform vec2 dimensions;
uniform vec4 filterArea;
uniform float time;
uniform vec4 fadeincolor;
uniform vec4 fadeoutcolor;
vec2 mapCoord( vec2 coord ) {
coord *= filterArea.xy;
return coord;
}
void main( void ) {
vec2 uv = vTextureCoord;
vec2 mappedCoord = mapCoord(uv) / dimensions;
float step2 = (1.0 - time);
float step3 = (1.0 - time) - 0.2;
step3 = clamp(step3, 0.0, 1.0);
float step4 = -0.0001;
vec4 color = fadeincolor;
color = mix(color, fadeoutcolor, smoothstep(step2, step3, mappedCoord.x));
color = mix(color, fadeoutcolor, smoothstep(step3, step4, mappedCoord.x));
gl_FragColor = color;
}`