How to display text sequentially using P5.js deviceMoved() function? - javascript

I am currently trying to make a program where the text changes as the phone moves every couple value(s) using the P5.JS deviceMoved() function.
(the gif below displays how i wanted the text to change eventually as the device moved)
As seen on the code below, I've put all the text in the array and I wanted to change the index to +1 each time say the move value ads 30 and repeat until all the text is gone.
let button;
let permissionGranted = false;
let nonios13device = false;
let cx, cy
let value = 0;
var myMessages = ["The", "Quick", "Brown", "Fox", "Jumped", "Over", "The", "Lazy", "Dog"];
var index = 0;
function setup() {
createCanvas(windowWidth, windowHeight);
}
function draw() {
background(255)
text(myMessages[index], width / 2, height / 2);
fill(value);
text(value, width / 3, height / 3);
textSize(30)
}
function deviceMoved() {
value = value + 5;
if (value > 255) {
value = 0;
}
}
function onMove() {
var currentValue = value + 30;
if (value = currentValue) {
index++;
return;
}
if (index >= myMessages.length) {
index = 0;
}
}
<script src="https://cdn.jsdelivr.net/npm/p5#1.3.1/lib/p5.js"></script>
I think my problem is within the onMove function, where I need to define the current value and what values could change the text, I'm fairly new at this so any insight/solution to do this would be highly appreciated :)
Thank you!

There are several issues related to the onMove function. First and foremost it is never called, and unlike deviceMoved it is not a special function that p5.js automatically invokes. Additional issues:
function onMove() {
// You create a currentValue variable that is just value + 30.
// Within the same function, checking if value is >= currentValue,
// assuming that is what you intended, will be fruitless because it
// is never true.
// What you probably want to do is declare "currentValue" as a global
// variable and check the difference between value and currentValue.
var currentValue = value + 30;
// This is the assignment operator (single equal sign), I think you meant
// to check for equality, or more likely greater than or equal to.
if (value = currentValue) {
index++;
// You definitely do not want to return immediately here. This is where
// you need to check for the case where index is greater than or equal
// to myMessages.length
return;
}
if (index >= myMessages.length) {
index = 0;
}
}
Here's a fixed version:
function deviceMoved() {
value = value + 5;
if (value > 255) {
// When value wraps around we need to update currentValue as well to
// keep track of the relative change.
currentValue = 255 - value;
value = 0;
}
onMove();
}
let currentValue = 0;
function onMove() {
if (value - currentValue >= 30) {
// Update currentValue so that we will wait until another increment of
// 30 before making the next change.
currentValue = value;
index++;
// We only need to make this check after we've incremented index.
if (index >= myMessages.length) {
index = 0;
}
}
}
In order to test this out on my mobile device (iOS 14) I had to add some code to request access to the DeviceMotionEvent, and host it in an environment using HTTPS and not embedding in an iframe. You can see my code on glitch and run it live here.

Related

Why is my maze generator not detecting if a cell has been visited in p5.js?

I am trying to make a maze generator, and almost everything is working so far. I have been able to set my position to a random pos, and then I repeat the standard() function. In the function, I add pos to posList, and then I choose a random direction. Next, I check if the cell has been visited by running through all of the posList vectors in reverse. I haven't executed the code that backtracks yet. If visited = false then I move to the square and execute the yet-to-be-made path() function. However, for some reason, the mover just doesn't detect if a cell has been visited or not. I am using p5.js. What am I doing wrong?
var posList = [];
var pos;
var tempo;
var boole = false;
var direc;
var mka = 0;
function setup() {
createCanvas(400, 400);
//Set up position
pos = createVector(floor(random(3)), floor(random(3)));
frameRate(1)
}
//Choose a direction
function direct(dire) {
if(dire === 0) {
return(createVector(0, -1));
} else if(dire === 1) {
return(createVector(1, 0));
} else if(dire === 2) {
return(createVector(0, 1));
} else {
return(createVector(-1, 0));
}
}
/foLo stands fo forLoop
function foLo() {
//If we have checked less than three directions and know there is a possibility for moving
if(mka < 4) {
//tempoRARY, this is what we use to see if the cell has been visited
tempo = createVector(pos.x + direct(direc).x, pos.y + direct(direc).y);
//Go through posList backwards
for(var i = posList.length - 1; i >= 0; i --) {
//If the cell has been visited or the cell is off of the screen
if(tempo === posList[i]) {
//Change the direction
direc ++;
//Roll over direction value
if(direc === 4) {
direc = 0;
}
//Re-execute on next frame
foLo();
//The cell has been visited
boole = false;
//Debugging
console.log(direc)
mka++;
} else if(tempo.x < 0 || tempo.x > 2 || tempo.y < 0 || tempo.y > 2) {
direc ++;
if(direc === 4) {
direc = 0;
}
foLo();
boole = false;
console.log(direc)
mka++;
}
}
//If it wasn't visited (Happens every time for some reason)
if(boole === true) {
//position is now the temporary value
pos = tempo;
console.log("works")
mka = 0;
}
}
}
function standard() {
//Add pos to posList
posList.push(pos);
//Random direction
direc = floor(random(4));
//Convert to vector
direct(direc);
foLo();
//Tracks pos
fill(255, 255, 0);
rect(pos.x*100+50, pos.y*100+50, 50, 50)
}
function draw() {
background(255);
fill(0);
noStroke();
//draw grid
for(var i = 0; i < 4; i ++) {
rect(i*100,0,50,350);
rect(0, i*100, 350, 50);
}
standard();
boole = true;
console.log(pos)
console.log(posList);
}
Your issue is on the line where you compare two vectors if(tempo === posList[i]) {: This will never be true.
You can verify that with the following code (in setup() for example):
const v1 = new p5.Vector(1, 0);
const v2 = new p5.Vector(1, 0);
const v3 = new p5.Vector(1, 1);
console.log(v1 === v2) // false
console.log(v1 === v3) // false
This is because despite having the same value v1 and v2 are referencing two different objects.
What you could do is using the p5.Vector.equals function. The doc has the following example:
let v1 = createVector(10.0, 20.0, 30.0);
let v2 = createVector(10.0, 20.0, 30.0);
let v3 = createVector(0.0, 0.0, 0.0);
print(v1.equals(v2)); // true
print(v1.equals(v3)); // false
This might not give you a working algorithm because I suspect you have other logical errors (but I could be wrong or you will debug them later on) but at least this part of the code will do what you expect.
Another solution is to use a Set instead of your list of positions. The cons of this solution is that you will have to adapt your code to handle the "out of grid" position situation. However when you want to keep track of visited items a Set is usually a great solution because the access time is constant. That this means is that to define is a position has already been visited it will always take the same time (you'll do something like visitedSet.has(positionToCheck), whereas with your solution where you iterate through a list the more cells you have visited to longer it will take to check if the cell is in the list.
The Set solution will require that you transform your vectors before adding them to the set though sine, has I explained before you cannot simply compare vectors. So you could check for their string representation with something like this:
const visitedCells = new Set();
const vectorToString = (v) => `${v.x},{$v.y}` // function to get the vector representation
// ...
visitedCells.add(vectorToString(oneCell)); // Mark the cell as visited
visited = visitedCells.has(vectorToString(anotherCell))
Also has a general advice you should pay attention to your variables and functions name. For example
// foLo stands fo forLoop
function foLo() {
is a big smell: Your function name should be descriptive, when you see your function call foLo(); having to find the comment next to the function declaration makes the code less readable. You could call it generateMaze() and this way you'll know what it's doing without having to look at the function code.
Same for
//tempoRARY, this is what we use to see if the cell has been visited
tempo = createVector(pos.x + direct(direc).x, pos.y + direct(direc).y);
You could simply rename tempo to cellToVisit for example.
Or boole: naming a boolean boole doesn't convey a lot of information.
That could look like some minor details when you just wrote the code but when your code will be several hundred lines or when you read it again after taking several days of break, you'll thank past you for taking care of that.

How to use a variable

I have a question / problem about a variable.
I have two page, in the first one I recover data and in the second one I do some operations.
ActivityPage.js (the first one)
recoverActivity() {
// this function check every second if the size of array > 1000
// this call only a function in the other page (Operations)
Operations.write({
arrayTimestamp: this.arrayTimestamp,
// other things
});
}
//this function when the user click a stop button.
stopActivity() {
Actions.Operations({
arrayTimestamp: this.arrayTimestamp,
});
}
And the I have another page
Operations.js:
//this is called from the first page directly
write(objectData) {
//...
this.timestampCheck(objectData.arrayTimestamp);
//...
}
//this is call from the ComponentDidMount of the second page.
stopClick() {
//...
this.timestampCheck(this.props.arrayTimestamp);
//...
}
Now my problem is in this timestampCheck function:
timestampCheck(timestamp) {
var int_max = 65536;
this.base = 0;
var diff = "";
var start = parseInt(this.contatore);
for (let i = 0; i < timestamp.length; i++) {
let timestamp = parseInt(timestamp[i]);
diff = (this.base + timestamp) - start;
if (diffDestro < 0) {
this.base+= int_max;
diff += this.base;
}
this.tempoReale.push(diff);
}
}
This function is called from the two function stopClick and write and there I have a variable this.base. Now I don't want that this variable loose his value when it leaves the functions timestampCheck. For example the arrayTimestamp has a size > 1000 an so it call the write() functions. here calculations are made and the value of this.base is set.
At this point, if the user clicks the stop key, the stopClick () function is called which calls the same timestampCheck function and must resume the previous value of this.base and not start from scratch.
How do you think I can do it?
thank you so much.
Just use a variable outside of the function to store the new value.
So outside of the function:
var countingValue = 0;
function timestampCheck(timestamp) {
var int_max = 65536;
this.base = 0;
var valueToUse = countingValue > 0 ? countingValue : this.base;
var diff = 0;
var start = parseInt(this.contatore);
for (let i = 0; i < timestamp.length; i++) {
let timestamp = parseInt(timestamp[i]);
diff = (valueToUse + timestamp) - start;
if (diffDestro < 0) {
valueToUse += int_max;
diff += valueToUse;
}
this.tempoReale.push(diff);
countingValue = countingValue + diff;
}
}
So what I have done here is create a variable outside of the function named countingValue with an initial value of 0.
Then underneath the initialisation of this.base I have used a type of If statement known as a ternary operator which says if the current countingValue is more than 0 then we will store that value in a variable named valueToUse otherwise we will use the this.base value and store it in the valueToUse variable.
In the rest of the code I have used the valueToUse variable for the computations now instead of this.base.
Note: I changed your variable diff to an integer because it was a string. You may want to review this and swap a couple of variables around if it's not exactly what you want.

What's a better way to initialize with zero or increment for objects?

I'm writing analytics and I have to initialize counter counts for (keys) hours, days, weeks, years so as to get frequency of user activity. I need to create a hit count for respective time and increment accordingly. Visits are fed via a loop.
I have this working but I'm not sure if the code below is ideal to do so.
if(!analytics.users[message.user].counts.hourly[hour]) {
analytics.users[message.user].counts.hourly[hour] = 0;
}
analytics.users[message.user].counts.hourly[hour] += 1;
if(!analytics.users[message.user].counts.daily[day]) {
analytics.users[message.user].counts.daily[day] = 0;
}
analytics.users[message.user].counts.daily[day] += 1;
...
I've tried the x = x + 1 || 0 method but that hasn't worked.
Also, is there a way I can set up a function for this?
You could use a function which take the object and the key and perfoms the check and update.
function increment(object, key) {
if (!object[key]) object[key] = 0;
++object[key];
}
Call with
increment(analytics.users[message.user].counts.hourly, hour);
I've tried the x = x + 1 || 0
You almost got it. It should either be:
x = x || 0;
x++;
Or
x = x + 1 || 1;
So, change your code to:
analytics.users[message.user].counts.hourly[hour] =
(analytics.users[message.user].counts.hourly[hour] + 1) || 1
If analytics.users[message.user].counts.hourly[hour] is undefined, the increment operation returns NaN. This is a falsy value. So, it takes 1
You can create a simple increment function like the one below. It first checks for the key to be initialized and if not, it will initialize it to 0. The next line with the increment is safe to execute since the key was previously created.
let message = {
user: "user"
}
let analytics = {
users: {
"user": {
counts: {
}
}
}
}
function incrementAnalytics(analytics, period) {
analytics[period] = analytics[period] || 0;
++analytics[period];
}
let test = analytics.users[message.user].counts;
incrementAnalytics(test, "hourly");
incrementAnalytics(test, "hourly");
incrementAnalytics(test, "daily");
console.log(test);
Cheers!

Javascript - How do I clear out a previous value in a DIV?

i'm making a game where 2 players are fighting one another.
I have it setup where the document writes the objects hp out (100). However, when I make a event where the player suffers 10 damage, it should write out 90 in the hp bar. Instead it writes out 10090.
How can I get it where the previous value gets updated, rather than it continuing to write beside the previous value?
function player (hp, mana, stamina){
this.hp = hp;
this.mana = mana;
this.stamina = stamina;
}
function npc (hp, mana, stamina) {
this.hp = hp;
this.mana = mana;
this.stamina = stamina;
}
var alistar = new player (100, 50, 30);
var dragon = new npc (100, 50, 30);
document.getElementById("hp").innerHTML += alistar.hp;
if ( 0 < 1) {
alistar.hp = alistar.hp - 10;
document.getElementById("hp").innerHTML += alistar.hp;
}
Doing the = sign works, but it removed any HTML words I had in there. I suppose I can make a 2nd div box for my HTML needs and keep the value seperate.
Just put = symbol instead of +=:
The = operator overwrite the previous value. On the other hand, the += is the union between the + operator and the = operator, and is the "shortway" to achieve the next:
For example, if you want to add a value to a variable you can do this:
var a = 3,
value = 10; /* Your value, i.e. 10 */
a = a + value; /* a values 13 */
BUT, you can get the same result using the += operators:
var a = 3,
value = 10; /* Your value, i.e. 10 */
a = += value; /* This adds the value of a to the value of value variable. */
As you can think, the value of a is 13, too as the below example.
Regarding to your code...
CODE:
if ( 0 < 1) {
alistar.hp = alistar.hp - 10;
document.getElementById("hp").innerHTML = alistar.hp; /* UPDATE */
}
if ( 0 < 1) {
alistar.hp = alistar.hp - 10;
document.getElementById("hp").innerHTML = alistar.hp;
}
+= is concatenating the values and adding them together (seemingly in string format). Instead, you want to use "=" to assign the value of the hp to the hp element, overwriting the existing innerHTML.

Animate counter using Javascript

I have a couple of fairly simple javascript functions which animate the transition of a number, going up and down based on user actions. There are a number of sliders on the page which within their callback they call recalculateDiscount() which animates the number up or down based on their selection.
var animationTimeout;
// Recalculate discount
function recalculateDiscount() {
// Get the previous total from global variable
var previousDiscount = totalDiscount;
// Calculate new total
totalDiscount = calculateDiscount().toFixed(0);
// Calculate difference
var difference = previousDiscount - totalDiscount;
// If difference is negative, count up to new total
if (difference < 0) {
updateDiscount(true, totalDiscount);
}
// If difference is positive, count down to new total
else if (difference > 0) {
updateDiscount(false, totalDiscount);
}
}
function updateDiscount(countUp, newValue) {
// Clear previous timeouts
clearTimeout(animationTimeout);
// Get value of current count
var currentValue = parseInt($(".totalSavingsHeader").html().replace("$", ""));
// If we've reached desired value, end
if (currentValue === newValue) { return; }
// If counting up, increase value by one and recursively call with slight delay
if (countUp) {
$(".totalSavingsHeader").html("$" + (currentValue + 1));
animationTimeout = setTimeout("updateDiscount(" + countUp + "," + totalDiscount + ")", 1);
}
// Otherwise assume we're counting down, decrease value by one and recursively call with slight delay
else {
$(".totalSavingsHeader").html("$" + (currentValue - 1));
animationTimeout = setTimeout("updateDiscount(" + countUp + "," + totalDiscount + ")", 1);
}
}
The script works really well for the most part however there are a couple of problems. Firstly, older browsers animate more slowly (IE6 & 7) and get confused if the user moves the slider again whilst it is still within the animation.
Newer browsers work great EXCEPT for on some occasions, if the user moves the slider mid-animation, it seems that it starts progressing in the wrong direction. So for updateDiscount() gets called with a new value and a directive to count up instead of down. As a result the animation goes the wrong direction on an infinite loop as it will never reach the correct value when it's counting in the wrong direction.
I'm stumped as to why this happens, my setTimeout() experience is quite low which may be the problem. If I haven't provided enough info, just let me know.
Thank you :)
Here is how you use setTimeout efficiently
animationTimeout = setTimeout(function {
updateDiscount(countUp,totalDiscount);
},20);
passing an anonymous function help you avoid using eval.
Also: using 1 millisecond, which is too fast and will freeze older browsers sometimes. So using a higher which will not even be noticed by the user can work better.
Let me know if this works out for you
OK think it's fixed...
Refactored code a little bit, here's final product which looks to have resolved bug:
var animationTimeout;
function recalculateDiscount() {
var previousDiscount = parseInt(totalDiscount);
totalDiscount = parseInt(calculateDiscount());
if (($.browser.msie && parseFloat($.browser.version) < 9) || $.browser.opera) {
$(".totalSavingsHeader").html("$" + totalDiscount);
}
else {
if (previousDiscount != totalDiscount) {
clearTimeout(animationTimeout);
updateDiscount(totalDiscount);
}
}
}
function updateDiscount(newValue) {
var currentValue = parseInt($(".totalSavingsHeader").html().replace("$", ""));
if (parseInt(currentValue) === parseInt(newValue)) {
clearTimeout(animationTimeout);
return;
}
var direction = (currentValue < newValue) ? "up" : "down";
var htmlValue = direction === "up" ? (currentValue + 1) : (currentValue - 1);
$(".totalSavingsHeader").html("$" + htmlValue);
animationTimeout = setTimeout(function () { updateDiscount(newValue); }, 5);
}
Will give points to both Ibu & prodigitalson, thank you for your help :)

Categories

Resources