-2

I have a game, https://e4494s.neocities.org/bounce.html, where the player can mess around with various variables and modify the physics of the simulation. I want to add a button that will take the user to a separate page where there are no text boxes or anything and the values they modified are stored in the URL so they can send it to somebody or save it for themselves. For example, if they modify bounciness to be 0.5 and gravity to -0.25, then clicking the Get Link button would send them to https://e4494s.neocities.org/fullscreenbounce.html/bounciness=0.5;gravity=-0.25. (I would be fine with any other way of storing them there, such as /0.5/0.25 or any other method). The problem is, when I go to this link, it is trying to go to the page "bounciness=0.5;gravity=-0.25" which doesn't exist on my website. But I know there IS some way to store variables in the URL, like for example Mr. Doob's game Voxels. As I make more Voxels, the URL changes and I can simply copy that URL and it will have the exact thing I built every time I go to it.

So how would I go about incorporating that into my game?

  • Welcome to Stack Overflow. Please edit your question to include details of what you have tried so far and the code you used in a [minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) so we can see what is happening and be able to help. – FluffyKitten Jul 29 '20 at 16:44

2 Answers2

0

I'd recommend you have a read of this related issue: Adding a parameter to the URL with JavaScript

Although you might want to look into using local storage instead (unless you are looking to use these as sharing links). Local storage will allow the values to be saved in the user's browser and still be there if they reload the page with no query parameters. Take a look at this one: https://www.w3schools.com/html/html5_webstorage.asp

  • Hi Tom, I think the link you provided to the other question is a good one, but the OP specifically says "the values they modified are stored in the URL _so they can send it to somebody_ or save it for themselves" — so it is for a sharing link like you mention. – Stephen P Jul 29 '20 at 16:53
0

One way to store accessible, redundant javascript data is using json. So the full parameterization of your game could be represented by the following string:

{ "bounciness": 0.5, "gravity": -0.25, "friction": 1.2, "windVector": { "ang": 2.7314, "mag": 4.23 } }

If that string was stored in a variable called dataString, you could do the following:

let { bounciness, gravity, friction, windVector } = JSON.parse(dataString);

Now the trick is to get the value in dataString into the URL. Json is good for arbitrary values, but it does not embed properly into a url. We need to make the additional step of encoding the json into a form that does fit in a url. One such encoding is base64, and base64 encoding already exists via the global btoa function (mdn) So the process will look like:

original raw data -> json data -> base64 encoded json data

The value to be inserted into the url, if the raw data is held in a variable called params, would be:

let params = { bounciness: 0.5, gravity: -0.25, friction: 1.2, windVector: { ang: 2.7314, mag: 4.23 } }
let valueForUrl = btoa(JSON.stringify(params));
console.log(valueForUrl);

Here's an example where, as the raw data is updated, the url value automatically updates:

let rawData = { "bounciness": 0.5, "gravity": -0.25, "friction": 1.2, "windVector": { "ang": 2.7314, "mag": 4.23 } }

let resultJson = document.querySelector('.result.json');
let resultBase64 = document.querySelector('.result.base64');

let elems = [ 'bounciness', 'gravity', 'friction', 'windVector-ang', 'windVector-mag' ]
  .map(v => document.querySelector(`[name="${v}"]`));

let [ bElem, gElem, fElem, waElem, wmElem ] = elems;

let fullUpdate = () => {
  if (document.querySelector(':invalid')) {
    resultJson.innerHTML = 'Invalid input';
    resultBase64.innerHTML = 'Invalid input';
    return;
  }
  
  let json = JSON.stringify(rawData);
  resultJson.innerHTML = json;
  resultBase64.innerHTML = btoa(json);
  
};
let updateElem = (elem, obj, prop) => {
  elem.value = obj[prop].toString();
  elem.addEventListener('input', evt => {
    if (elem.matches(':valid')) obj[prop] = parseFloat(elem.value, 10);
    fullUpdate();
  });
};

updateElem(bElem, rawData, 'bounciness');
updateElem(gElem, rawData, 'gravity');
updateElem(fElem, rawData, 'friction');
updateElem(waElem, rawData.windVector, 'ang');
updateElem(wmElem, rawData.windVector, 'mag');
fullUpdate();
input { display: block; }
input:valid { background-color: rgba(0, 150, 0, 0.2); }
input:invalid { background-color: rgba(150, 0, 0, 0.2); }

p { margin: 0; margin-top: 5px; }

.result {
  font-family: monospace;
  border: 2px solid #a0a0a0;
  margin-top: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
<p>Bounciness</p>
<input type="text" pattern="[-+]?[0-9]+([.][0-9]+)?" name="bounciness" />
<p>Gravity</p>
<input type="text" pattern="[-+]?[0-9]+([.][0-9]+)?" name="gravity" />
<p>Friction</p>
<input type="text" pattern="[-+]?[0-9]+([.][0-9]+)?" name="friction" />
<p>Wind Angle</p>
<input type="text" pattern="[-+]?[0-9]+([.][0-9]+)?" name="windVector-ang" />
<p>Wind Magnitude</p>
<input type="text" pattern="[-+]?[0-9]+([.][0-9]+)?" name="windVector-mag" />

<p>JSON</p>
<p class="result json"></p>
<p>Base64</p>
<p class="result base64"></p>

Now when a new page loads with a supplied url, you can convert back from base64 (using atob) to json, and then back from json to raw data. Assume the value in the url is in a variable urlData:

let urlData = 'eyJib3VuY2luZXNzIjowLjUsImdyYXZpdHkiOi0wLjI1LCJmcmljdGlvbiI6MS4yLCJ3aW5kVmVjdG9yIjp7ImFuZyI6Mi43MzE0LCJtYWciOjQuMjN9fQ';
console.log(JSON.parse(atob(urlData)));

Note that base64 is not the only possible encoding (and it may be more inefficient than other encodings!)

Gershom Maes
  • 7,358
  • 2
  • 35
  • 55