feat(jogo): expediente dos mortos, jogo de zumbis em primeira pessoa
Etapa 1 inteira (logica com 100% de cobertura, cena 3D, toque, sons, bancada de desempenho, e2e) e a base da etapa 2 (mapa novo no Tiled, texturas, imagens dos itens, sons conferidos, golpe recortado e medido). Pagina /jogo fora do menu e do sitemap ate a medicao no celular.
This commit is contained in:
1 parent
c7d09d63d4
commit
67b32fcab3
118 files changed
+16730
No files matched your search
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* Regulador de qualidade: numa janela, mede o p95 do intervalo entre quadros e o do trabalho de JS de cada quadro,
|
||||
* e sobe/desce degraus de `NIVEIS`. Sem estado no módulo.
|
||||
*/
|
||||
|
||||
import { NIVEIS, REGULADOR } from "./valores";
|
||||
|
||||
export type Regulador = {
|
||||
nivel: number;
|
||||
/** Primeiro nível cujo `pixelRatio` cabe no do aparelho; o regulador nunca sobe acima dele. */
|
||||
topo: number;
|
||||
/** Intervalos entre quadros da janela atual, em ms. */
|
||||
intervalos: number[];
|
||||
/** Tempo de JS de cada quadro da janela atual (lógica + chamada de render), em ms. */
|
||||
trabalhos: number[];
|
||||
/** Soma dos intervalos da janela atual, em ms. */
|
||||
somaDaJanela: number;
|
||||
/** Tempo seguido de janelas com folga, em ms. */
|
||||
folga: number;
|
||||
/** Soma dos intervalos aceitos desde o início, em ms. */
|
||||
tempo: number;
|
||||
/** Valor de `tempo` na última subida; null se nunca subiu. */
|
||||
tempoDaSubida: number | null;
|
||||
/** Desceu logo depois de subir: não sobe mais. */
|
||||
subidaTravada: boolean;
|
||||
/** Descer não adiantou duas vezes seguidas: o limite é da tela, não da nossa carga. Não muda mais de nível. */
|
||||
travado: boolean;
|
||||
/** p95 do intervalo na janela que acabou de descer; null se a janela anterior não desceu. */
|
||||
p95DaDescida: number | null;
|
||||
descidasSemGanho: number;
|
||||
};
|
||||
|
||||
const ULTIMO = NIVEIS.length - 1;
|
||||
|
||||
export function criarRegulador(pixelRatio: number): Regulador {
|
||||
// abaixo do menor `pixelRatio` (zoom de afastar), vale o primeiro degrau com o menor
|
||||
const tela = Math.max(pixelRatio, NIVEIS[ULTIMO].pixelRatio);
|
||||
const topo = NIVEIS.findIndex((n) => n.pixelRatio <= tela);
|
||||
return {
|
||||
nivel: topo,
|
||||
topo,
|
||||
intervalos: [],
|
||||
trabalhos: [],
|
||||
somaDaJanela: 0,
|
||||
folga: 0,
|
||||
tempo: 0,
|
||||
tempoDaSubida: null,
|
||||
subidaTravada: false,
|
||||
travado: false,
|
||||
p95DaDescida: null,
|
||||
descidasSemGanho: 0,
|
||||
};
|
||||
}
|
||||
|
||||
export function nivelAtual(r: Regulador): (typeof NIVEIS)[number] {
|
||||
return NIVEIS[r.nivel];
|
||||
}
|
||||
|
||||
/** Ordena a própria janela: ela é esvaziada logo depois. */
|
||||
function p95(quadros: number[]): number {
|
||||
quadros.sort((a, b) => a - b);
|
||||
return quadros[Math.ceil(0.95 * quadros.length) - 1];
|
||||
}
|
||||
|
||||
function descer(r: Regulador, intervalo: number): void {
|
||||
r.folga = 0;
|
||||
if (r.nivel >= ULTIMO) return;
|
||||
r.nivel += 1;
|
||||
r.p95DaDescida = intervalo;
|
||||
const subiuHaPouco =
|
||||
r.tempoDaSubida !== null && r.tempo - r.tempoDaSubida < REGULADOR.trava;
|
||||
if (subiuHaPouco) r.subidaTravada = true;
|
||||
}
|
||||
|
||||
function acumularFolga(r: Regulador, duracao: number): void {
|
||||
r.folga += duracao;
|
||||
if (r.folga < REGULADOR.subida) return;
|
||||
if (!r.subidaTravada && r.nivel > r.topo) {
|
||||
r.nivel -= 1;
|
||||
r.tempoDaSubida = r.tempo;
|
||||
}
|
||||
r.folga = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Na janela seguinte a uma descida: se o intervalo não melhorou `REGULADOR.ganho`, conta uma descida sem ganho; na
|
||||
* segunda seguida, volta os degraus e trava. Devolve true se travou.
|
||||
*/
|
||||
function conferirGanho(r: Regulador, intervalo: number): boolean {
|
||||
const antes = r.p95DaDescida;
|
||||
r.p95DaDescida = null;
|
||||
if (antes === null) return false;
|
||||
if (intervalo <= antes * (1 - REGULADOR.ganho)) {
|
||||
r.descidasSemGanho = 0;
|
||||
return false;
|
||||
}
|
||||
r.descidasSemGanho += 1;
|
||||
if (r.descidasSemGanho < REGULADOR.descidasSemGanho) return false;
|
||||
r.nivel = Math.max(r.topo, r.nivel - r.descidasSemGanho);
|
||||
r.travado = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
function fecharJanela(r: Regulador): void {
|
||||
const intervalo = p95(r.intervalos);
|
||||
const trabalho = p95(r.trabalhos);
|
||||
const duracao = r.somaDaJanela;
|
||||
r.intervalos.length = 0;
|
||||
r.trabalhos.length = 0;
|
||||
r.somaDaJanela = 0;
|
||||
if (conferirGanho(r, intervalo)) return;
|
||||
if (intervalo > REGULADOR.limite) descer(r, intervalo);
|
||||
else if (trabalho < REGULADOR.folgaDeTrabalho) acumularFolga(r, duracao);
|
||||
else r.folga = 0;
|
||||
}
|
||||
|
||||
export function amostrar(
|
||||
r: Regulador,
|
||||
intervaloMs: number,
|
||||
trabalhoMs: number,
|
||||
): number {
|
||||
if (r.travado || intervaloMs > REGULADOR.ignorar) return r.nivel;
|
||||
r.intervalos.push(intervaloMs);
|
||||
r.trabalhos.push(trabalhoMs);
|
||||
r.somaDaJanela += intervaloMs;
|
||||
r.tempo += intervaloMs;
|
||||
if (r.somaDaJanela >= REGULADOR.janela) fecharJanela(r);
|
||||
return r.nivel;
|
||||
}
|
||||
Reference in new issue
Block a user