룰렛프로그램 원하는 값이 나오도록 수정하는 코드 fps 깨짐 현상
본문
구글 돌려돌려 돌림판 이라는 프로그램을 제가 원하는 값이 나오도록 수정하였습니다.
Onstop 이라는 함수에서 시작값과 각 항목의 가중치를 계산하여 공간을 할당하고 그 공간 내에서 랜덤값을 주어 원하는 곳에서 멈추게 프로그래밍 하였는데 약 3퍼센트의 확률로 항상 40도가 부족하게 멈춥니다.
콘솔로그로 모든 값들을 찍어 보았는데, 수학적 연산에는 아무런 문제가 없어보입니다. 연산에 무리가 와 랜더링 문제가 올 수도 있다고 판단해서 함수들에 연산도 나누어 봤고, 매번 랜더링을 새로 새로 고침 해보았지만 별다른 소득은 없었습니다. requestAnimationFrame을 사용 하고 있고 (해당 기능은 60fps로 맞춰주는 함수)
너무 높아 프로그램에는 30fps로 제한을 두고 있길래 제한을 해제해 보았더니(최대 60fps까지) 항상 뒤쪽으로 3번째가 나와야한다면 4가 나왔는데 해제 했더니 앞쪽으로(2가 선택)되는 현상이 발생 하였습니다.
연산에 문제가 있는것 같지는 않는데 어디서 문제가 나는것인지 도저히 모르겠습니다... 고수님들 도와주세요 ㅠㅠ 몇가지 함수를 첨부하겠습니다.
(랜덤값이 문제인거 같아 로그를 찍어봐도 문제가 있지는 않았습니다. )
stop 함수는 룰렛이 멈출때 작동하는 함수입니다.
Onupdate 함수는 멈춤 버튼을 눌렀을 때 작동되며 시간이 지날때마다 속도를 느리게하여 최종에는 멈추는 역할을 하는 함수입니다.
function Roulette() {
var R = {
dirty: true,
rotation: 0,
$button: $('#roll')
};
window.R = R;
function OnStart() {
try {
$(document.body).css('background', bgColor);
R.canvas = document.querySelector('canvas');
R.ctx = R.canvas.getContext('2d', true);
R.size = { width: R.canvas.width, height: R.canvas.height };
R.center = { x: R.size.width / 2 , y: R.size.height / 2 };
window.radius = Math.min(Math.min(R.size.width, R.size.height) * 0.5 * 0.9, R.size.height / 2 - 40);
R.bufferCanvas = document.createElement('canvas');
R.bufferCanvas.width = R.size.width;
R.bufferCanvas.height = R.size.height;
R.buffer = R.bufferCanvas.getContext('2d', true);
R.buffer.textAlign='center';
//수정 20230703
R.animFrameId = requestAnimationFrame(OnUpdate);
} catch(e) { console.log(e); }
}
function OnUpdate(timestamp) {
R.deltaTime = timestamp - (R.lastTimestamp || timestamp);
R.FPS = (R.deltaTime && (R.deltaTime > 0)) ? Math.round(1000 / R.deltaTime) : 0;
R.deltaTime = Math.min(R.deltaTime, 100);
requestAnimationFrame(OnUpdate);
if (0 < R.deltaTime && R.deltaTime < 17) {
return;
}
// this frame
//R.$button.blur();
//console.log(R.FPS);
if (R.stopping) {
if (Date.now() - R.stopping > 15 * 1000) {
R.angularVelocity = 0;
delete R.stopping;
}
}
if (R.angularDamping) {
R.angularVelocity -= Math.max(20, Math.min(R.angularVelocity * 0.5, R.angularDamping)) * (R.deltaTime / 1000);
}
if (R.angularVelocity <= 0) {
R.angularVelocity = 0;
if (R.launched && typeof R.onStop === 'function') {
R.launched = false;
R.onStop();
}
}
if (R.angularVelocity) {
R.rotation += R.angularVelocity * (R.deltaTime / 1000);
while (R.rotation < 0) R.rotation += 360;
while (R.rotation >= 360) R.rotation -= 360;
}
if (R.prevRotation != R.rotation) {
R.dirty = true;
}
R.prevRotation = R.rotation;
R.ctx = R.canvas.getContext('2d');
// render
OnRender();
// next frame
R.lastTimestamp = timestamp;
//requestAnimationFrame(OnUpdate);
}
function drawArc(option, name, split) {
if (!split || (split && !name)) {
R.buffer.save();
R.buffer.translate(option.x, option.y);
R.buffer.rotate(DEG2RAD(option.rotation - 90));
R.buffer.beginPath();
R.buffer.moveTo(0, 0);
R.buffer.arc(0, 0, option.radius, 0, DEG2RAD(option.angle));
R.buffer.closePath();
R.buffer.fillStyle = option.color;
R.buffer.fill();
R.buffer.beginPath();
R.buffer.arc(0, 0, option.radius, 0, DEG2RAD(option.angle));
R.buffer.strokeStyle = window.line_color;
R.buffer.lineWidth = 3;
R.buffer.stroke();
R.buffer.restore();
}
if (!split || (split && name)) {
// text
R.buffer.save();
R.buffer.translate(option.x, option.y);
R.buffer.rotate(DEG2RAD(option.rotation - 90 + option.angle / 2));
R.buffer.beginPath();
R.buffer.moveTo(0, 0);
R.buffer.font = window.font2;
R.buffer.strokeStyle = fontStrokeStyle; // 'black';
R.buffer.lineWidth = 5;
R.buffer.strokeText(name, option.radius / 2, 8);
//R.buffer.fillStyle = window.line_color;
R.buffer.fillStyle = 'white';
R.buffer.fillText(name, option.radius / 2, 8);
R.buffer.restore();
}
}
function OnRender() {
if (!R.dirty) return;
R.dirty = false;
// clear
R.buffer.fillStyle = bgColor;
R.buffer.fillRect(0, 0, R.size.width, R.size.height);
//R.buffer.clearRect(0, 0, R.size.width, R.size.height);
if (R.FPS) {
R.buffer.font = window.font;
R.buffer.fillStyle = window.line_color;
R.buffer.fillText(R.FPS + 'FPS', 50, R.center.y - window.radius - 7);
}
// shadow
R.buffer.shadowBlur = 15;
R.buffer.shadowColor = 'black';
drawArc({ x: R.center.x, y: R.center.y + 15 + 5, radius: window.radius - 5, rotation: 0, angle: 360, color: bgColor }, '');
R.buffer.shadowBlur = 0;
drawArc({ x: R.center.x, y: R.center.y + 15, radius: window.radius, rotation: 0, angle: 360, color: bgColor }, '');
//
R.current = null;
if (R.Items && R.Items.length > 0) {
R.lastAngle = 0;
R.Items.forEach(function(item) {
R.currentAngle = 360 - R.rotation;
while (R.currentAngle < 0) R.currentAngle += 360;
while (R.currentAngle >= 360) R.currentAngle -= 360;
// if (item.angleSum - item.angle <= R.currentAngle && R.currentAngle <= item.angleSum) {
// R.current = item.name;
// }
drawArc({ x: R.center.x, y: R.center.y + 15, radius: window.radius,
rotation: R.rotation + R.lastAngle, angle: item.angle, color: item.color }, null, true);
R.lastAngle += item.angle;
//if (R.lastAngle >= 360) R.lastAngle -= 360;
});
R.lastAngle = 0;
R.Items.forEach(function(item) {
R.currentAngle = 360 - R.rotation;
while (R.currentAngle < 0) R.currentAngle += 360;
while (R.currentAngle >= 360) R.currentAngle -= 360;
if (item.angleSum - item.angle <= R.currentAngle && R.currentAngle <= item.angleSum) {
R.current = item.name;
R.currentColor = item.color;
}
drawArc({ x: R.center.x, y: R.center.y + 15, radius: window.radius,
rotation: R.rotation + R.lastAngle, angle: item.angle, color: item.color }, item.name, true);
R.lastAngle += item.angle;
//if (R.lastAngle >= 360) R.lastAngle -= 360;
});
} else {
drawArc({ x: R.center.x, y: R.center.y + 15, radius: window.radius,
rotation: R.rotation-45, angle: 180, color: getColor(0) }, '돌려돌려');
drawArc({ x: R.center.x, y: R.center.y + 15, radius: window.radius,
rotation: R.rotation-45+180, angle: 180, color: getColor(1) }, '돌림판');
}
// pin
R.buffer.beginPath();
R.buffer.moveTo(R.size.width / 2 , R.center.y - window.radius + 20);
R.buffer.lineTo(R.size.width / 2 - 5, R.center.y - window.radius + 5 );
R.buffer.lineTo(R.size.width / 2 - 5, R.center.y - window.radius + 0 );
R.buffer.lineTo(R.size.width / 2 + 5, R.center.y - window.radius + 0 );
R.buffer.lineTo(R.size.width / 2 + 5, R.center.y - window.radius + 5 );
R.buffer.closePath();
R.buffer.fillStyle = window.pinColor;
R.buffer.fill();
R.buffer.stroke();
if (R.current) {
//R.buffer.shadowBlur = 1;
R.buffer.font = window.font;
if (R.currentColor) {
R.buffer.strokeStyle = window.line_color; // 'black';
R.buffer.lineWidth = 5;
R.buffer.strokeText(R.current, R.size.width / 2, R.center.y - window.radius - 7);
}
R.buffer.fillStyle = R.currentColor || window.line_color;
R.buffer.fillText(R.current, R.size.width / 2, R.center.y - window.radius - 7);
//R.buffer.shadowBlur = 0;
}
// 가운데 점
// R.buffer.beginPath();
// R.buffer.arc(R.center.x, R.center.y + 15, 3, 0, 2 * Math.PI);
// R.buffer.fill();
R.ctx.drawImage(R.bufferCanvas, 0, 0);
}
R.Launch = function() {
R.launched = true;
R.angularVelocity = 4 * 360; // 4 * 360;
R.angularDamping = 0;
delete R.stopping;
}
R.Stop = function() {
console.log('--------------------------');
console.log('Start of Stop function');
console.log('--------------------------');
console.log('Initial R.rotation value at onStop: ', R.rotation);
R.stopping = Date.now();
console.log('Stopping timestamp: ', R.stopping);
R.angularDamping = 360; // adjust this value according to your needs
chrome.storage.local.get(['numValue'], function(result) {
console.log('Retrieved numValue from storage: ', result.numValue);
var ulElement = document.querySelector("ul");
var liElements = ulElement.querySelectorAll("li");
var liCount = liElements.length - 1;
var totalWeight = 0;
for (var i = 0; i < liCount; i++) {
var weight = parseFloat(liElements[i].querySelector('.item-weight').getAttribute('data-weight'));
totalWeight += weight;
}
console.log('Total weight: ', totalWeight);
var numvalue = result.numValue;
var input = parseInt(numvalue);
console.log('Parsed input value: ', input);
if (isNaN(input) || !input || input > liCount) {
input = Math.floor(Math.random() * liCount) + 1;
}
console.log('Input after potential random assignment: ', input);
var cumulativeWeights = new Array(liCount);
var cumulativeWeight = 0;
for (var i = 0; i < liCount; i++) {
var weight = parseFloat(liElements[i].querySelector('.item-weight').getAttribute('data-weight'));
cumulativeWeight += weight;
cumulativeWeights[i] = cumulativeWeight;
}
console.log('Cumulative weights array: ', cumulativeWeights);
var stopAngle;
if (input > 1) {
stopAngle = (cumulativeWeights[input - 2] / totalWeight) * 360;
} else {
stopAngle = 0;
}
console.log('Stop angle before offset: ', stopAngle);
var stopRange = ((cumulativeWeights[input - 1] / totalWeight) * 360) - stopAngle;
stopAngle += Math.random() * stopRange;
console.log('Stop angle after adjustments: ', stopAngle);
stopAngle = 75.335 - stopAngle;
if (stopAngle < 0) {
stopAngle += 360;
}
var decelerationAngle = R.angularDamping;
stopAngle -= decelerationAngle;
if (stopAngle < 0) {
stopAngle += 360;
}
console.log('Stop angle after deceleration: ', stopAngle);
R.rotation = stopAngle;
console.log('Final rotation value: ', R.rotation);
if (R.animFrameId !== undefined) {
cancelAnimationFrame(R.animFrameId);
R.animFrameId = undefined;
}
console.log('--------------------------');
console.log('End of Stop function');
console.log('--------------------------');
});
}
OnStart();
}
답변을 작성하시기 전에 로그인 해주세요.