yukinovel
Version:
Yukinovel is a simple web visual novel engine.
204 lines (203 loc) • 8.27 kB
JavaScript
import { MainMenuRenderer } from './ui/MainMenuRenderer.js';
import { DialogueRenderer } from './ui/DialogueRenderer.js';
import { SceneRenderer } from './ui/SceneRenderer.js';
import { ModalRenderer } from './ui/ModalRenderer.js';
import { SaveLoadRenderer } from './ui/SaveLoadRenderer.js';
import { ConfirmModal } from './ui/ConfirmModal.js';
export class UIRenderer {
constructor(game) {
this.game = game;
}
render(container) {
this.container = container;
this.container.id = 'container';
this.container.className = 'vn-container vn-no-select';
this.createUIStructure();
this.initializeRenderers();
this.attachEventListeners();
}
createUIStructure() {
/**
* @description phần Main Menu container
* Cha: container gốc
*/
this.mainMenuContainer = document.createElement('div');
this.mainMenuContainer.id = 'container-menu';
this.mainMenuContainer.className = 'vn-main-menu-container';
this.container.appendChild(this.mainMenuContainer);
/**
* @description phần Game container
* Cha: container gốc
*/
this.gameContainer = document.createElement('div');
this.gameContainer.id = 'container-game';
this.gameContainer.className = 'vn-game-container';
this.container.appendChild(this.gameContainer);
/**
* @description phần Background Layer
* Cha: gameContainer
*/
this.backgroundElement = document.createElement('div');
this.backgroundElement.id = 'background-game';
this.backgroundElement.className = 'vn-background';
this.gameContainer.appendChild(this.backgroundElement);
/**
* @description phần Character layout
* Cha: gameContainer
*/
this.characterContainer = document.createElement('div');
this.characterContainer.id = 'container-character';
this.characterContainer.className = 'vn-character-container';
this.gameContainer.appendChild(this.characterContainer);
/**
* @description phần UI layer
* Cha: gameContainer
*/
this.uiContainer = document.createElement('div');
this.uiContainer.id = 'container-ui';
this.uiContainer.className = 'vn-ui-container';
this.gameContainer.appendChild(this.uiContainer);
/**
* @description phần Dialogue container
* Cha: uiContainer
*/
this.dialogueContainer = document.createElement('div');
this.dialogueContainer.id = 'container-dialogue';
this.dialogueContainer.className = 'vn-dialogue-container';
this.uiContainer.appendChild(this.dialogueContainer);
/**
* @description phần Choices container
* Cha: uiContainer
*/
this.choicesContainer = document.createElement('div');
this.choicesContainer.id = 'container-choices';
this.choicesContainer.className = 'vn-choices-container';
this.uiContainer.appendChild(this.choicesContainer);
/**
* @description phần Controls container
* Cha: uiContainer
*/
this.controlsContainer = document.createElement('div');
this.controlsContainer.id = 'container-controls';
this.controlsContainer.className = 'vn-controls-container';
this.uiContainer.appendChild(this.controlsContainer);
this.createControlButtons();
/**
* @description phần Log container
* Cha: uiContainer
*/
this.logContainer = document.createElement('div');
this.logContainer.id = 'container-log';
this.logContainer.className = 'vn-log-container';
this.uiContainer.appendChild(this.logContainer);
}
initializeRenderers() {
this.mainMenuRenderer = new MainMenuRenderer(this.game, this.mainMenuContainer);
this.dialogueRenderer = new DialogueRenderer(this.game, this.dialogueContainer, this.choicesContainer);
this.sceneRenderer = new SceneRenderer(this.game, this.backgroundElement, this.characterContainer);
this.modalRenderer = new ModalRenderer(this.game, this.logContainer);
this.saveLoadRenderer = new SaveLoadRenderer(this.game);
this.saveLoadRenderer.render(this.container);
this.confirmModal = ConfirmModal.getInstance(this.game);
this.confirmModal.render(this.container);
}
createControlButtons() {
const langManager = this.game.getLanguageManager();
const controls = [
{ key: 'Enter', action: langManager.getText('ui.next'), onClick: () => this.handleNext() },
{ key: 'Esc', action: langManager.getText('exit.title', 'Thoát'), onClick: () => this.modalRenderer.showExitConfirm() },
{ key: 'S', action: langManager.getText('ui.save'), onClick: () => this.showSavePanel() },
{ key: 'L', action: langManager.getText('ui.load'), onClick: () => this.showLoadPanel() },
{ key: 'H', action: langManager.getText('ui.history'), onClick: () => this.modalRenderer.toggleLog() }
];
controls.forEach(control => {
const controlDiv = document.createElement('div');
controlDiv.className = 'vn-control-item';
controlDiv.onclick = control.onClick;
const keyDiv = document.createElement('div');
keyDiv.textContent = control.key;
keyDiv.className = 'vn-control-key';
const actionDiv = document.createElement('div');
actionDiv.textContent = control.action;
actionDiv.className = 'vn-control-action';
controlDiv.appendChild(keyDiv);
controlDiv.appendChild(actionDiv);
this.controlsContainer.appendChild(controlDiv);
});
}
handleNext() {
this.dialogueRenderer.handleNext();
}
attachEventListeners() {
this.dialogueContainer.addEventListener('click', () => {
this.handleNext();
});
const gameContainer = document.querySelector('#container-game');
document.addEventListener('keydown', (e) => {
if (gameContainer.style.display === 'none')
return;
if (e.code === 'Space' || e.code === 'Enter') {
e.preventDefault();
this.handleNext();
}
else if (e.code === 'Escape') {
e.preventDefault();
this.modalRenderer.showExitConfirm();
}
else if (e.code === 'KeyS') {
e.preventDefault();
this.showSavePanel();
}
else if (e.code === 'KeyL') {
e.preventDefault();
this.showLoadPanel();
}
else if (e.code === 'KeyH') {
e.preventDefault();
this.modalRenderer.toggleLog();
}
});
}
showMainMenu() {
this.mainMenuRenderer.show();
this.gameContainer.style.display = 'none';
}
hideMainMenu() {
this.mainMenuRenderer.hide();
this.gameContainer.style.display = 'block';
}
updateScene(scene) {
this.sceneRenderer.updateScene(scene);
}
updateSceneWithFade(scene, shouldFadeBackground, backgroundAnimation) {
this.sceneRenderer.updateSceneWithFade(scene, shouldFadeBackground, backgroundAnimation);
}
updateDialogue(dialogue) {
this.dialogueRenderer.updateDialogue(dialogue);
this.sceneRenderer.updateCharacterSprites(dialogue);
}
showChoices(choices) {
this.dialogueRenderer.showChoices(choices);
}
getTypewriterSpeed() {
return this.dialogueRenderer.getTypewriterSpeed();
}
setTypewriterSpeed(speed) {
this.dialogueRenderer.setTypewriterSpeed(speed);
}
getSceneRenderer() {
return this.sceneRenderer;
}
showCredits() {
console.log('Credits modal');
}
showSavePanel() {
this.saveLoadRenderer.showSavePanel();
}
showLoadPanel() {
this.saveLoadRenderer.showLoadPanel();
}
getConfirmModal() {
return this.confirmModal;
}
}