Skip to content

Instantly share code, notes, and snippets.

@jespertheend
Last active March 15, 2024 20:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jespertheend/53cddb4a15055d63ab2a9c0585265eda to your computer and use it in GitHub Desktop.
Save jespertheend/53cddb4a15055d63ab2a9c0585265eda to your computer and use it in GitHub Desktop.
A function that allows you to convert a 2d vector into a single byte and back into a vector. Useful when you want to send player joystick input over the network.
import { mod, Vec2 } from "https://cdn.jsdelivr.net/npm/renda@0.3.0/dist/renda.min.js";
const RING_SEGMENTS = 36;
const RING_COUNT = 7;
// https://www.desmos.com/calculator/zpob0tj445
/**
* Normalizes a Vec2 (between -1 and 1) and returns a byte (a value between 0 and 255)
* which can be used to turn it back into a Vec2 using {@linkcode byteToVec2d}.
* Naturally, a lot of precision is lost when using this operation.
* @param {import("$renda").Vec2} vec
*/
export function vec2dToByte(vec) {
if (vec.magnitude == 0) return 0;
const theta = vec.clockwiseAngleTo(new Vec2(-1, 0));
const ba = mod(Math.round(((Math.PI - theta) / (2 * Math.PI)) * RING_SEGMENTS - 1), RING_SEGMENTS) + 1;
const bb = Math.round(vec.magnitude * RING_COUNT) * RING_SEGMENTS - RING_SEGMENTS;
return ba + bb;
}
/**
* Converts a byte which was generated by {@linkcode vec2dToByte} back into a Vec2.
* Naturally, a lot of precision is lost when using this operation.
* @param {number} byte
*/
export function byteToVec2d(byte) {
const radius = Math.floor(((byte - 1) / RING_SEGMENTS) + 1) / RING_COUNT;
const theta = byte / RING_SEGMENTS * Math.PI * 2;
return new Vec2(Math.cos(theta) * radius, Math.sin(theta) * radius);
}
import { byteToVec2d, vec2dToByte } from "./vec2ToByte.js";
import { assertVecAlmostEquals, Vec2 } from "https://cdn.jsdelivr.net/npm/renda@0.3.0/dist/renda.min.js";
/**
* @param {number} byte
*/
function assertIsByte(byte) {
if (Math.round(byte) != byte) {
throw new Error(`${byte} is not an integer`);
}
if (byte < 0 || byte > 255) {
throw new Error(`${byte} is not within the 0-255 range`);
}
}
Deno.test({
name: "Some common vectors stay exactly the same",
fn() {
const tests = [
new Vec2(),
new Vec2(0, 1),
new Vec2(0, -1),
new Vec2(1, 0),
new Vec2(-1, 0),
];
for (const test of tests) {
const byte = vec2dToByte(test);
assertIsByte(byte);
const vec = byteToVec2d(byte);
assertVecAlmostEquals(vec, test);
}
},
});
Deno.test({
name: "Other vectors stay roughly the same",
fn() {
const tests = [
new Vec2(),
new Vec2(0, 1),
new Vec2(0, -1),
new Vec2(1, 0),
new Vec2(-1, 0),
];
for (const test of tests) {
const byte = vec2dToByte(test);
assertIsByte(byte);
const vec = byteToVec2d(byte);
assertVecAlmostEquals(vec, test);
}
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment