Slight error in calculations - javascript

I'm trying to build a game somewhat like Wheel of Fortune, actually it's done but there seems to a weird issue I can't figure out.
Here's the wheel itself, as you can see the values are spaced evenly, each having a 15 ° slice.
To spin the wheel I generate a random number which will be the amount of rotation in degrees, I animate the wheel and everything is fine but when the rotation stops I have to get the value from the wheel which stops at the top-center position so I though this would solve it:
wheelValues = [
1000, 3250, 1800, 1000, 1200, 3750, 5000, 1000, 3000, 1600, 1000, 3500,
1000, 2000, 1000, 2750, 1000, 4000, -1, 1000, 2500, 1400, 1000, 2250
];
if (toAngle > 360)
{
toAngle = toAngle - (Math.floor(toAngle / 360) * 360);
}
arrIndex = Math.floor(toAngle / 15) + 1;
result = wheelValues[arrIndex];
where toAngle is the random spin I generate which can be between 370 and 1440.
This method works in about 8/9 times out of 10 and I can actually get the correct value the wheel stops at but I can't really understand why sometimes the value is off (and sometimes really off, not even near the correct value).

You're adding 1 to your array index for some reason.
array indexes start from 0.

Two problems I can see;
Firstly, this line:
if (toAngle > 360)
If toAngle == 360, I believe this will produce an error, as you will skip the 'modulus' section and toAngle will finally be 24 (larger than your dataset)
Second:
arrIndex = Math.floor(toAngle / 15) + 1;
No need to +1 this, as you will never get your first value, and on occasion you will exceed the array bounds.
Also, as to why you get odd values, have you tried to write some simple code to debug your assumptions? Write a loop, that iterates from 370 to 1440 (your stated input boundaries) and see what your calculation comes up with for each value. Print it to a file, or screen and you can quickly scan to see where the issues might be.

BTW, it's probably best if you make your random number an even multiple of 15 degrees in the first place, then you don't need all that rounding and flooring, e.g.
function randDeg() {
var epoch = 360; // minimum value
var max = 1440; // maximum value to return
var step = 15; // even multiple to return
var t = Math.random() * (max - epoch) | 0;
t -= t % 15;
return t + epoch;
}
Will return a number n where epoch <= n <= max and n%15 = 0.

Related

How to increment the number from 00.000000 to 48.853373 in few seconds by 0.00001

I am using map coordinates as a part of website logo. (2.378628, 48.853373).
What I want to do, is count both numbers from 0.000000 so they reach given points during the same time (3-5 seconds), incrementing by 0.000001. How is that possible? This crashes my computer, and setInterval does sth every ms, which is not enough.
while (i < 48.853373) {
i = i + 0.000001;
$('.js-center-lat').text(i);
}
Sounds like you want to "animate" the floating point number to count up to a defined value.
Have you considered third party libraries, like CountUp.js?
CountUp.js is a dependency-free, lightweight JavaScript "class" that can be used to quickly create animations that display numerical data in a more interesting way.
Quick example on how to use it:
var options = {
  useEasing: true,
  useGrouping: true,
  separator: '',
  decimal: '.',
};
var demo = new CountUp('myTargetElement', 0, 2.415543, 6, 2.5, options);
if (!demo.error) {
  demo.start();
} else {
  console.error(demo.error);
}
Hope this helps!
You take the time when you started the animation (startTime), and you have value how long the animation should last (duration).
For each animation step you can calculate the percentage of the animation.
And with that percentage you can count up multiple values.
let startTime = Date.now();
let duration = 3000;
function updateText() {
let percent = Math.min(1, (Date.now() - startTime) / duration);
// Math min ensures that percent does not become larger then 1
$('.val1').text(50 * percent); // 0 - 50
$('.val2').text(33 * percent); // 0 - 33
$('.val3').text(13 + 10 * percent); // 13 - 23
if (percent <= 1) {
requestAnimationFrame(updateText)
}
}
updateText();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="val1">
</div>
<div class="val2">
</div>
<div class="val3">
</div>

Javascript: Set variable to either 1 or -1

I'm trying to get an object that moves in a different direction when you click on it, and each time you click on it it goes faster. I have it almost functioning, but I can't get the program to exclude 0 or do only -1 or 1; I can only do a random number between -1 and 1. This means that if it hits zero, it can't progress.
(The following code is built with a Javascript engine called "Crafty". Non-javascript parts are commented as best as I can.)
Crafty.init(400,320, document.getElementById('game')); // Creates canvas
// Create variables
var speed = 10;
var min = -1;
var max = 1;
// Create a 32px by 32px red box
var square = Crafty.e('2D, Canvas, Color, Mouse, Motion')
.attr({x: 50, y: 50, w: 32, h: 32})
.color('red')
// When the red box is clicked, move it in a random direction. Make it go faster each time.
.bind('Click', function(MouseEvent){
speed *= 2;
var vel = square.velocity();
var direction = ((Math.random() * (max - min)) + min);
vel.x;
vel.y;
vel.x = (speed *= direction);
vel.y = (speed *= direction);
});
Change to this line
var direction = (Math.random()) > .5 ? 1 : -1;
It really comes down to this line:
var direction = ((Math.random() * (max - min)) + min);
If you store the acceptable values (-1 and 1) in an array, you can make the random choose one of those based on the length of the array. By storing the values in an array, you not only make the process simpler, but it is extensible because you can always add new values later, if desired.
function getRandom(){
var acceptable = [-1, 1];
// Get a random number from 0 to 1 (the length of the array, 2, will never be reached)
var direction = Math.floor(Math.random() * acceptable.length);
console.log(acceptable[direction]); // Choose either array element 0 or element 1
}
// Run this code snippet a few times and you'll see that you only get -1 and 1
getRandom();
getRandom();
getRandom();
getRandom();
You can also remove the two lines declaring the max and min variables as they are no longer needed.

Do something after every 180 degrees

I have a div with some text which I would like to rotate 360 degrees for x amount of times but I would also like to modify the text every 180 degrees. how can I achieve this in Jquery or Javascript?
So far, I am stuck on this as I don't know of a way to monitor the rotation.
$('.pie_chart').css({'transform' : 'rotate(2000deg)'});
I looked at this post thinking that I could utilize the solution but it didn't work for me, or I might be just using it wrong: CSS rotation cross browser with jquery.animate()
This is very imprecise but it gets the idea across and should be enough to get you on the right track
function AnimateRotate(angle) {
// caching the object for performance reasons
var $elem = $('#square');
var texts = ['text', 'another thing', 'one more thing', 'finally']
var maxRotations = Math.floor(angle / 180);
var rotations = 0;
var lastRotation = 0;
// we use a pseudo object for the animation
// (starts from `0` to `angle`), you can name it as you want
$({deg: 0}).animate({deg: angle}, {
duration: 2000,
step: function(now) {
// in the step-callback (that is fired each step of the animation),
// you can use the `now` paramter which contains the current
// animation-position (`0` up to `angle`)
$elem.css({
transform: 'rotate(' + now + 'deg)'
});
// Here we must allow ourselves some margin for error
// We are making 4 rotations in 2 seconds, so in theory
// The box will be at the 180 degrees every half a second
// but in actuality it never is at exactly 180 degree except at the star and end
// Trial and error has shown that +6 degrees is more or less accurate,
// you could do some math to get a better precision
// We don't want to update the text at 0 degrees
if(now % 180 <= 6 && rotations > 0) {
// Shift off the first text and use that for the new text
$("#text").html(texts.shift());
rotations++;
} else if(now % 180 >= 177) {
$("#text").html(texts.shift());
rotations++;
}
}
})
};
AnimateRotate(720);

CSS transform rotate always clockwise without exceeding 360 degrees

Im designing a clock, for the "hands" Im using a combination of JS and CSS to make an smooth animation, converting second, minutes and hours to its corresponding degree in the analog clock:
function clock() {
var t = moment(),
s = t.seconds() * 6,
a = t.minutes() * 6,
o = t.hours() % 12 / 12 * 360 + (a / 12);
$(".hour").css("transform", "rotate(" + o + "deg)");
$(".minute").css("transform", "rotate(" + a + "deg)");
$(".second").css("transform", "rotate(" + s + "deg)");
}
setInterval(clock, 1000);
The problem is, after getting to 360 degrees I don't want the variable to keep increasing forever, I just return to 0 and start again, but, CSS makes the hands turn anticlockwise making an undesired effect.
Example
I was thinking about removing the transition property using JS when im about to go from 360 to 0 and then put it in again, this may be a solution, but I wonder if there is a cleaner way.
It can't be done natively. A transition from 356 to 2 degrees will always go counter clockwise. If you don't mind the visible tick from 356 to 2 degrees, just remove the transition. But there's no reason to do that. Try to exploit the fact that rotate can take any sane value, also above 360 degrees. So instead of returning to 0, just let the clock continue to increase the value "endlessly" (the highest int value in js is 9007199254740991, so you'll have to refresh the browser after a few million years... :)).
You can keep track of rotations so far in a separate counter object outside the setInterval callback like this:
var counter = {
s: 0,
a: 0,
o: 0
};
var previous = null;
Then you want to store all values from the previous iteration somewhere, and compare the current values to the previous ones. If necessary, increase the appropriate counter by one.
if(previous){
if(s < previous.s){
counter.s += 1;
}
if(a < previous.a){
counter.a += 1;
}
if(o < previous.o){
counter.o += 1;
}
}
previous = {
s: s,
a: a,
o: o
};
Then just set the multiplied degree value in your inline css. This way you will still have access to the pure values of s etc in case you need those for something.
$(".second").css("transform", "rotate(" + (s + 360 * counter.s) + "deg)");
Working fiddle: https://jsfiddle.net/dannyjolie/tccroo1q/6/

Javascript: Calculating the Remainder not working?

I'm working on a game where the player / enemy has a balance bar with 3 overlays. What i'm trying to do is manipulate the 1st overlay so it goes fully across the bar by percentages.
Example: first overlay is 50% of enemy's balance. Then moves into another 'phase' or 'state. Then that overlay is gone and the second overlay is triggered and starts to decrease as well.
The width of the bar is 200 pixels, so what i'm trying to do is say "hey, if 50% of the enemies balance is gone, THEN trigger/animate the 2nd overlay.
The problem i'm running into is the remainder line. When I hit the enemy for say.. 10 balance damage of 200. It will give me the proper percentage left AND the proper remainder left. But once I hit 50%, the remainder = 0! This is where that line or function no longer works properly and it breaks the design pattern of what I want to do. Here is a example in the console log.
balanceCounter: function (character, boss){
var percentage = Math.floor((boss.balance/200) * 100)
var remain = 100 % percentage; // <--- This is not working properly
console.log(percentage);
console.log(remain);
if (character.virtue == "hero"){
if (percentage > 49){
$("#bossbalanceoverlay2").animate({
width: percentage * 2 - (remain * 2)
}, 200)
}
else
$("#bossbalanceoverlay1").animate({
width: percentage * 2 - (remain * 2)
}, 200);
}
**click attack button**
97 // <--- Percent
3 // <--- Remainder
**click attack button**
95 // <--- Percent
5 // <--- Remainder
**click attack button**
92 // <--- Percent
8 // <--- Remainder
(When i hit the 50% mark)
**click attack button**
50 // <--- Percent
0 // <--- Remainder **Why 0?**
**click attack button**
47 // <--- Percent
6 // <--- Remainder **Why 6 instead of 3?**
**click attack button**
45 // <--- Percent
10 // <--- Remainder **Why 10 instead of 5?**
You probably want to do this, instead of %:
var remain = 100 - percentage;
You want remain + percentage to always add up to 100, so this is a subtraction you need, not a modulo operation.
It is normal that with % (modulo) you get zero when the percentage is 50, because 100 is a multiple of 50 and so there is no remainder.
The problem your facing is that % returns the remainder.
100 % 45 => divisible by 45 twice, remainder = 10.
100 % 50 => divisible by 50 twice, remainder = 0.
What you want is remain = 100 - percentage
For starters I would add missing semicolons.
Secondly it looks like your else bracket is missing curly braces { }, which could cause both blocks to be hit depending on how your code is formatted.
Thirdly I would read up on the % operator, you may be overthinking it ;)

Categories