//============================================================================= // Sphinx-Spinner.js //============================================================================= /*: * @plugindesc Graphique sous forme de sprite * @author Sphinx * @help * //========================================================================== * // Plugin : Sphinx-Spinner * // Date : 7 janvier 2020 * // Auteur : Sphinx * //========================================================================== * Ce plugin permet de créer facilement un spinner comportant des valeurs * personnalisées au moyen de la nouvelle classe SphinxSpinner. * * Usage : * spinner = new SphinxSpinner({ * width: 640, // Largeur du spinner * height: 480, // Hauteur du spinner * values: [ "Pile", "Face" ], // Valeurs à afficher dans la roue * colors: [ "red", "blue" ], // Couleurs CSS du dégradé de la roue * speed: { * start: 1, // Vitesse initiale sur une échelle de 1 à 100 * max: 50, // Vitesse finale sur une échelle de 1 à 100 * acceleration: 5 // Pourcentage d'accélération de la roue * } * }); * * Une fois le spinner créé, deux options se présentent : * - Soit vous surveillez dans la méthode update de votre scène si le * spinner s'est arrêté au moyen de la fonction : * spinner.isStopped() * puis vous récupérez sa valeur par le biais la propriété : * spinner.value * - Soit vous ajoutez un listener qui sera exécuté une et une seule fois * lorsque le spinner s'arrête : * spinner.setStopHandler(callback); * La valeur du spinner sera passée à la fonction de callback. * /!\ Si vous passez le contexte à la fonction de callback au moyen * de la méthode callback.bind(this); pensez à passer aussi la référence * au spinner au moyen de callback.bind(this, spinner); pour pouvoir * récupérer la valeur du spinner. * * Outre le spinner, la classe SphinxSpinner intègre une méthode statique qui * permet de récupérer un objet bitmap correspondant à l'ID d'une icône : * bitmap = SphinxSpinner.getIcon(id); * * Dépendances : - Sphinx-Polyfill * * @param arrow * @text Flèche du spinner * @type file * @default arrow * @dir img/system * @require 1 * * @param click * @text Icone de clic du spinner * @type file * @default click * @dir img/system * @require 1 */ if(!Game_System.prototype.getColor) { Game_System.prototype.getColor = function(color) { d = document.createElement("div"); d.style.color = color; document.body.appendChild(d); color = window.getComputedStyle(d).color; document.body.removeChild(d); color = color.replace(/^rgb\((\d+), (\d+), (\d+)\)$/, "$1-$2-$3").split("-"); for(i = 0; i < color.length; ++i) { color[i] = parseInt(color[i], 10).toString(16); if(color[i].length == 0) color[i] = "00"; else if(color[i].length == 1) color[i] = "0" + color[i]; } return color.join(""); }; } Scene_Boot.sphinxSpinnerLoadSystemImages = Scene_Boot.loadSystemImages; Scene_Boot.loadSystemImages = function() { Scene_Boot.sphinxSpinnerLoadSystemImages.call(this); ImageManager.reserveSystem(PluginManager.parameters("Sphinx-Spinner")["arrow"]); ImageManager.reserveSystem(PluginManager.parameters("Sphinx-Spinner")["click"]); } function SphinxSpinner() { this.initialize.apply(this, arguments); }; SphinxSpinner.prototype = Object.create(Sprite_Base.prototype); SphinxSpinner.prototype.constructor = SphinxSpinner; SphinxSpinner.getIcon = function(iconIndex) { var bitmap = ImageManager.loadSystem('IconSet'); var pw = Window_Base._iconWidth; var ph = Window_Base._iconHeight; var icon = new Bitmap(pw, ph); var sx = iconIndex % 16 * pw; var sy = Math.floor(iconIndex / 16) * ph; icon.blt(bitmap, sx, sy, pw, ph, 0, 0); return icon; }; SphinxSpinner.prototype.initialize = function(config) { Sprite_Base.prototype.initialize.call(this); // Configuration this.config = config || {}; this.width = config.width || 640; this.height = config.height || 420; this.config.values = this.config.values || [ "Pile", "Face" ]; this.config.colors = this.config.colors || [ "red", "blue" ]; this.config.speed = this.config.speed || {}; this.config.speed.start = this.config.speed.start || 1; this.config.speed.max = this.config.speed.max || 50; this.config.speed.acceleration = this.config.speed.acceleration || 5; // Internal variables this.speed = this.config.speed.start / 100; this.touched = false; this.stopped = false; this.frames = 0; this.anchor.x = 0.5; this.anchor.y = 0.5; this.indexes = []; for(i = 0; i < this.config.values.length; ++i) { this.indexes.push(i); } // Spinner sprite this.spinner = new Sprite_Button(); this.spinner.anchor.x = 0.5; this.spinner.anchor.y = 0.5; this.spinner.bitmap = new Bitmap(this.width, this.height); this.spinnerContext = this.spinner.bitmap._context; this.spinnerContext.translate(this.width / 2, this.height / 2); this.addChild(this.spinner); // Drawing this.drawClick(); this.drawArrow(); this.drawSpinner(); // Click listener this.spinner.setClickHandler(SphinxSpinner.prototype.onTouch.bind(this)); }; SphinxSpinner.prototype.update = function() { Sprite_Base.prototype.update.call(this); // Rotation this.spinner.rotation -= this.speed; // Scale of hand if(this._click.bitmap) { if(this.isBusy()) this._click.opacity = 0; else this._click.opacity = 255; this._click.scale.x = 1 - 0.5 * this.frames / 60; this._click.scale.y = 1 - 0.5 * this.frames / 60; if(this.frames == 60) this.frames = 0; this.frames++; } // Acceleration and deceleration if(this.speed < this.config.speed.max / 100 && !this.touched) this.speed *= 1 + this.config.speed.acceleration / 100; if(this.speed >= this.config.speed.start / 100 && this.touched) this.speed /= 1 + this.config.speed.acceleration / 100; else if(this.speed < this.config.speed.start / 100 && !this.stopped) this.stop(); }; SphinxSpinner.prototype.setStopHandler = function(callback) { if(this.stopped) callback(this.value); else this.callback = callback; }; SphinxSpinner.prototype.drawClick = function() { this._click = new Sprite_Base(); this._click.anchor.x = 0.5; this._click.anchor.y = 0.5; this.addChild(this._click); clickBitmap = ImageManager.loadSystem(PluginManager.parameters("Sphinx-Spinner")["click"]); clickBitmap.addLoadListener((() => { scale = Math.min(this.width, this.height) * 1 / 3 / clickBitmap.width; this._click.bitmap = new Bitmap(clickBitmap.width * scale, clickBitmap.height * scale); this._click.bitmap.blt(clickBitmap, 0, 0, clickBitmap.width, clickBitmap.height, 0, 0, this._click.bitmap.width, this._click.bitmap.height); }).bind(this)); }; SphinxSpinner.prototype.drawSpinner = function() { this.indexes.shuffle(); ray = Math.min(this.width, this.height) / 2 - 8; gradient = this.spinnerContext.createRadialGradient(0, 0, 0, 0, 0, ray); gradient.addColorStop(0, this.config.colors.shift()); for(i = 0; i < this.config.colors.length; ++i) { gradient.addColorStop((i + 1) * 1 / this.config.colors.length, this.config.colors[i]); } for(i = 0; i < this.indexes.length; ++i) { v = this.config.values[this.indexes[i]]; this.spinnerContext.beginPath(0, 0); this.spinnerContext.moveTo(0, 0); startAngle = i * 360 / this.indexes.length - 360 / 2 / this.indexes.length; nextAngle = i * 360 / this.indexes.length + 360 / 2 / this.indexes.length; this.spinnerContext.lineTo(ray * Math.cos(startAngle * Math.PI / 180), ray * Math.sin(startAngle * Math.PI / 180)); this.spinnerContext.arc(0, 0, ray, startAngle * Math.PI / 180, nextAngle * Math.PI / 180); this.spinnerContext.lineWidth = 2; this.spinnerContext.strokeStyle = "black"; this.spinnerContext.stroke(); this.spinnerContext.save(); this.spinnerContext.globalAlpha = 0.59765625; this.spinnerContext.fillStyle = gradient; this.spinnerContext.fill(); this.spinnerContext.restore(); this.spinnerContext.textAlign = "center"; this.spinnerContext.textBaseline = "middle"; this.spinnerContext.save(); this.spinnerContext.rotate(i * 360 / this.indexes.length * Math.PI / 180); if(v instanceof Bitmap) { x1 = ray / 2 * Math.cos(startAngle * Math.PI / 180); y1 = ray / 2 * Math.sin(startAngle * Math.PI / 180); x2 = ray / 2 * Math.cos(nextAngle * Math.PI / 180); y2 = ray / 2 * Math.sin(nextAngle * Math.PI / 180); size = Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)) / 2; scale = size / Math.max(v.width, v.height); this.spinner.bitmap.blt(v, 0, 0, v.width, v.height, ray * 4 / 5 - v.width * scale, -v.height * scale / 2, v.width * scale, v.height * scale); } else { fontSize = ray / (this.config.values.length / 2); this.spinner.bitmap.fontSize = fontSize; while(this.spinner.bitmap.measureTextWidth(v.toString()) > ray / 2) { fontSize--; this.spinner.bitmap.fontSize = fontSize; } this.spinnerContext.font = this.spinner.bitmap._makeFontNameText(); this.spinnerContext.fillText(v.toString(), ray * 3 / 4 - this.spinner.bitmap.measureTextWidth(v.toString()) / 4, 0); } this.spinnerContext.restore(); } }; SphinxSpinner.prototype.drawArrow = function() { this._arrow = new Sprite_Base(); this._arrow.anchor.x = 0.5; this._arrow.anchor.y = 0.5; this._arrow.x = Math.min(this.width, this.height) / 2 - this._arrow.width; this.addChild(this._arrow); arrowBitmap = ImageManager.loadSystem(PluginManager.parameters("Sphinx-Spinner")["arrow"]); arrowBitmap.addLoadListener((() => { scale = Math.min(this.width, this.height) * 1 / 4 / clickBitmap.width; this._arrow.bitmap = new Bitmap(arrowBitmap.width * scale, arrowBitmap.height * scale); this._arrow.bitmap.blt(arrowBitmap, 0, 0, arrowBitmap.width, arrowBitmap.height, 0, 0, this._arrow.bitmap.width, this._arrow.bitmap.height); }).bind(this)); }; SphinxSpinner.prototype.isBusy = function() { return this.speed < this.config.speed.max / 100 || this.touched; }; SphinxSpinner.prototype.isStopped = function() { return this.stopped; }; SphinxSpinner.prototype.onTouch = function() { if(this.isBusy()) return; this.touched = true; }; SphinxSpinner.prototype.stop = function() { this.stopped = true; this.speed = 0; i = Math.ceil((((this.spinner.rotation / Math.PI * 180) - 360 / 2 / this.config.values.length) % 360) / (360 / this.config.values.length)) * -1; this.value = this.indexes[i]; if(this.callback) this.callback(this.value); };