I have this fiddle http://jsfiddle.net/pp7oby62/. The fiddle consists of a paddle game with rocks being hurdled at a paddle on a 80x10 sensor grid. The function notify_player has two parameters which give me the location of the rocks and the paddle. My code looks like this:
defender.start(
function notify_player(rocks, paddle_y) {
var rocks_x = Math.max(rocks);
var rocks_y = Math.min(rocks);
var paddle_x = Math.max(paddle_y);
var paddle_yp = Math.min(paddle_y);
var deltaY = rocks_y - paddle_yp;
var deltaX = rocks_x - paddle_x;
var angleInRadians = Math.atan2(deltaY, deltaX);
var angleRound=Math.round(angleInRadians);
// random plan
var moves = [];
for (var i = 0; i < 22; i++) {
// -1, 0, 1 to move the fiddle up and down on the grid
//moves.push( Math.floor(Math.random()*3) - 1 );
if (angleInRadians >0) moves.push(-1);
else if (angleInRadians < 0) moves.push(0, 1, -1);
}
return moves;
}
);
The moves array controls the paddle moving up and down. As you can see I am calculating the angle in radians using the the information I get from the two parameters. But when I run it there's no effect on the movement of paddle when I give conditional loops stating that the angle is >0 or <0. But suppose I say:
if(angleInRadians!==0)
The paddle moves.
How could this be possible?
there's no effect on the movement of paddle when I give conditional loops stating that the angle is >0 or <0.
This could simply be when anleInRadians is zero - you've got a blind spot there.
But suppose I say: if(angleInRadians!==0) The paddle moves. How could this be possible?
The variable angleInRadians contains the value NaN. It is neither smaller nor greater than zero, as it's not a number - but it is definitely not zero. Yes, NaNs equality relations are a bit odd (it's not even equal to itself).
The reason why you are getting NaN here is that you're doing invalid mathematical operations. rocks is an array of objects (you really should log and inspect it), which you cannot call Math.min or .max on.
Btw, it doesn't even make sense to call min or max on a single value. And you won't get the paddle_x position by calling Math.max(paddle_y).
Related
I am making a sine calculator that will be able to evaluate the sine of complex numbers by using polar coordinates and calculating part of the infinite series that defines the sine function. The calculator seems to work fine if the magnitude of the inputted complex number is small. However, when the magnitude of the inputted complex number becomes large (over 40) the calculator stops working, as the system seems to be outputting the real and imaginary portions of the final result as NaN. Please may you help me make my calculator work for all complex inputs? Any help would be greatly appreciated. Here is my HTML and JS code:
var arr=[];
var result=[0,0];
function calc(){
var input=document.querySelector("input").value;
try{if(input.split("+").length == 1){
arr[0]=Number(input.split("-")[0])
arr[1]=-1*Number(input.split("-")[1].split("i").join(""))
if(input.split("-")[1].split("i").join("") === ""){
arr[1] = -1;
}
}else{
arr[0]=Number(input.split("+")[0])
arr[1]=Number(input.split("+")[1].split("i").join(""))
if(input.split("+")[1].split("i").join("") === ""){
arr[1] = 1;
}
}
}catch(e){if(input.split("i").length == 1){arr[0] = Number(input);arr[1]=0}}
for(var i=0;i<100;i++){
result[0] += ((-1)**i)*calcPower(2*i+1)[0]/factorialize(2*i+1)
result[1] += ((-1)**i)*calcPower(2*i+1)[1]/factorialize(2*i+1)
}
document.querySelector("div").innerText=result[0]+sign(result[1])+Math.abs(result[1])+"i";
result[0]=0;
result[1]=0;
}
function calcPower(pow){
var r=(arr[0]**2+arr[1]**2)**0.5;
if(Math.sign(arr[0])+Math.sign(arr[1]) == -2){
r *= -1}
r **= pow;
var real=Math.cos(Math.atan(arr[1]/arr[0])*pow)*r;
var imag=Math.sin(Math.atan(arr[1]/arr[0])*pow)*r;
return [real,imag];
}
function factorialize(factorial){
var result=1;
for(var i=1;i<=factorial;i++){result *= i};return result}
function sign(num){if(Math.sign(num) == -1){return "-"}else{return "+"}}
<input></input>
<button onclick=calc()>Take the sine of the complex number</button>
<br>
<div id=output style=font-size:20px></div>
I ran your code and the problem occurred on this line:
r **= pow;
When I used "54" as an input, the last iteration it could handle was r=54 & pow = 177, which produced 4.3022484685528774e+306. In the next iteration pow became 179, which produced Infinity, because it had exceeded the limits of 64 bit floats.
One way to deal with this issue is to use BigInt for the portions of your code that don't require the data after the decimal point. I made a fiddle here where you can see that BigInt can handle 54**179. https://jsfiddle.net/afyk6rbu/
const big = BigInt(54)**BigInt(179)
console.log(big.toString())
console.log(Number(big))
The toString shows that it has successfully calculated the values, but Number(big) shows that the number is too large to fit in a normal number. It must be brought back into the range of a 64 bit float before it can be used for trig.
I have some function:
function calc_degree(a,b,c,cnt) {
if(cnt==0) {
return a;
}
b = b+c;
a = a-b;
return calc_degree(a,b,c,cnt-1);
}
Shortly, it calcs degree of rotation some cicle, which rotation speed increase smoothly. Function returns summary degrees of the rotation. For example:
calc_degree(0,0,1.5,6*1000/time_out);
//a - start angle; b-value of increasing ratoation degree every tick.
//c-increase value; time_out - interval of rotation.
In this example, function returns summary degrees of rotation by 6 seconds.
So, how can I calc the "c" param, if I know the "a" and "cnt"? I need to get the increase value, knowing the summary degrees of rotation and time/tick. If my "a" value is 2790, I need to decrease it every time by "c" value and the last value of "a" must be zero.
Make it a proper recursion, with indices and all:
b[n] = b[n-1] + c => b[n] = b[0] + n*c
a[n] = a[n-1] - b[n] = a[n-1] - b[0] - n*c
results in
a[n] = a[0] - n*b[0] - n*(n+1)/2 * c
This shows you how to get c if a[0]=b[0]=0.
To get a[n]=b[n]=0, you would first need c=-b[0]/n and then c=-a[n]/(n*(n-1)/2). This only works if in the beginning 2*a[0] == (n-1)*b[0].
I cannot comment yet, so I'll add it here. LutzL answer is correct. The problem is that if you add more than one constraint to the problem (in your case requiring both a and b to go to 0) you are reducing the degrees of freedom of the problem. In your case you cannot make a go to zero smoothly (with both a and b 0) if there's not the relation stated by LutzL in the beginning. You can solve it by adding another degree of smoothness (ex: c[n] = c[n-1] + d.) But then you wont be able to make a, b and c tend to 0 without extra constraints.
I'm not able to make function trajgen() to calculate x and y and after three days put in trying I still can't find the solution. The whole program is over 200 lines so I'll cross my fingers you to find something false in the following 'problematic' function. :)
Take a look...
function trajgen(){
$(".reddot").remove();
x=xo;
y=yo;
$(".reddot").css({"top": y, "left": x});
isin=true;
while(isin==true){
x = xo + v0*Math.cos(angle)*time;
y = yo + v0*Math.sin(angle)*time - 0.5*g*Math.pow(time,2);
alert("x= "+x);
alert("y= "+y);
$("#frames").append('<div class = "reddot" style = "top: '+ y + 'px; left: '+ x +'px;"><img src="red.png" height="10" width="10"></div>');
time+=1;
isin=inchecker();
}
return;
}
function inchecker(){
if(y<Dy||y>Ay||x<Dx||x>Bx){
isin = false;
return isin;
}
isin = true;
return isin;
}
Now, when I alert x and y this thing returns me NaNs (i know what it means), for the both coordinates. Another interesting aspect is that function inchecker doesn't stop the buggy reddot appending after they get out of the div I'm using as a element where to draw my trajectory. Instead of getting parabolic arc I get infinitely vertically clonning/appending red points. All other variables work properly, x, y, xo, yo, speed, time... and so on are globals. Xo and yo I get as (0;0) from where to launch the projectile and I found out that all other variables work well, the only problem is with those x and y which I haven't used anywhere else so far. I assigned them with zeros but by now this doesn't change the unwillingness of my script to calculate x and y. #frames is the div where all those things happen. Please, help me and thanks in advance.
At the line where you compute x and y, either angle, v0, xo, or vo is null or not a number.
run a debugger and step through those lines, and check the values in place.
I have been hacking on this problem for a while and can't seem to find a solution (I am not friends with trigonometry).
I am trying to build an element that the user can "grab" and then rotate. I have it working except for one last feature I can't seem to figure out:
http://codepen.io/megakoresh/pen/WbLLzZ?editors=001
(it's long, but I am only asking about how the snapTo() function should work).
What I want is for the object snap to degrees based on the increments value. This means that if snap==true, the code should calculate the closest estimated targets to the point of release of the mouse and based on the direction of rotation smoothly rotate the object to that target rotation:
Since the object is 'grabbed', I calculate the offset at mousedown to object's current rotation, thats where it comes from, so it doesn't just snap to mouse.
So in this case the user rotates the object clockwise and releases the mouse when the objects rotation is between 90° and 45°. Since the direction (identified by the sign of angle variable) was positive, the target will be after the Current rotation.
The task is to calculate that target and then smoothly rotate the object to it.
The function I have written for it is based on by autoSpin() function (executes when spin==false), which takes a flipped time exponent multiplier delta (calculated from the time elapse since mouse was released). delta will decrease along a flipped exponent as time passes and so the angle slows down.
There is spinTo() function, please don't judge me I have a feeling it is very stupid:
function snapTo() {
var elapsed, delta;
increments = (typeof increments === 'number') ? Math.floor(increments) : 4;
var ia = 360 / increments; //increment angle - snapping points should occur "every ia degrees"
if (Math.abs(angle % ia) > 0) { //if user turned for more than 1 increment
var a = lastRot % ia; //check the distance from
if (angle > 0){ //positive direction
amplitude = 50; //if snapping is on, force amplitude
target = (lastRot - a) + ia;
}
if (angle < 0){ //negative direction
amplitude = -50;
target = lastRot - a;
}
} else { //cancel the rotation
target = rotation;
}
elapsed = Date.now() - timestamp; //time passed since mouse was released
delta = -amplitude * Math.exp(-elapsed / timeConstant); //the greater the time from mouse release, the smaller this value
if (delta > 0.5 || delta < -0.5) { //while delta is decreasing...
rotate(target - delta - offset);
snapFrame = requestAnimationFrame(snapTo); //keep rotation
} else {
rotate(target - offset); //when enough time passes (based on timeConstant), make one final rotation and stop
}
}
What am I doing wrong?
*le sigh
Ok well I had to figure it out on my own. If anyone wants to do this kind of thing, here is one way of doing it:
function snapTo() {
var elapsed, ease, diff;
increments = (typeof increments === 'number') ? Math.floor(increments) : 4;
var ia = 360 / increments; //increment angle - this is how large each increment will be
var a = last % ia; //check the distance from point of mouse release to the previous increment
if (movement>0) {
elapsed = Date.now() - timestamp; //time passed since mouse was released
ease = 1 - Math.exp((-3*elapsed)/timeConstant); //your easing function formula goes here
if(a > ia/2) { //if halfway through the increment...
target = (last - a) + ia; //target next increment
}
else { //else revert to previous increment to the point of mouse release
target = last - a;
}
diff = target - last; //difference between target and rotation at time of mouse release
if(ease < 0.95){ //this depends on your easing formula
rotate(last+diff * ease);
requestAnimationFrame(snapTo); //don't forget to RAF
} else { //and for your final frame...
rotate(last+diff); //make it snappy :P
}
console.log(last); //traces of debugging were found in this derelict question...
}
}
So in here
elapsed is the time passed since the mouse was released
increments is the argument provided by user: how many snapping points will be there
ia is the computed increment in degrees: 360/increments
last is the angle recorded on mouseup event - "Current rotation" in the diagram. It includes the offset (in my code, its just a "snapshot" of rotation at point of release, that is then also reversed in sign because in DOM the coordinate system is y-flipped and I don't like working with that).
a is how much bigger the last is than the previous nearest increment point.
diff is the "target" on the diagram - difference between final rotation and last
ease is just the value that changes according to your easing function, based on which you either continue calling RAF or finish the animation.
timeConstant is time in milliseconds for how long the animation will take. You can have this or not, depends on your easing formula
A good resource to read in general: Understanding Easing Functions
Also Desmos graphing calculator is quite good for developing easing formulas.
Oh and: in case anyone is wondering, it doesn't seem possible to pass any kind of non-time-related arguments to RAF callback functions. Seems to break it if I do. So the only solution is to define the increments value elsewhere in the code.
Codepen of the working function
Anyone got a better solution, I am all eyes.
I have this function which detects the collision between to objects. It is called within a Ticker (FPS 60). The if statement will run as long as the two objects are together. I think this has something to do with the ticker and it running the if every frame. What would be the best way to fix this so that for example when the two objects collided the person gets one point instead of four or ten.
function collDec(){
var minDistance = 10 + 10;
var xDist = circle.x - arrow.x;
var yDist = circle.y - arrow.y;
var distance = Math.sqrt(xDist*xDist + yDist*yDist);
if (distance < minDistance) {
Lpoints.text = "Points: " + ++pointsAm;
//console.log("HIT");
var dingSound = createjs.Sound.play("sound/ding.mp3");
//reset();
}
} // End of collDec
Have an int on each object, recently collided
If a collision occurs, set both recently collided on both objects to 2
At the start of every frame, decrement recently collided on all objects by 1 to a minimum of 0
If a collision occurs and recently collided is 1 or higher* on both objects, do not add points/play a sound but still increment recently collided.
*I think 'exactly 1' may be fine too. It seems to only matter in 'three balls collide simultaneously or near simultaneously' cases.