smoothretro82

PHYSICS FOLLOWER (update 3) orbit mode

Nov 25th, 2025 (edited)
84
0
Never
6
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.63 KB | None | 0 0
  1. // ======================================================
  2. // GLOBAL TOGGLES
  3. // ======================================================
  4.  
  5. // Orbit ON/OFF for everyone:
  6. let GLOBAL_ORBIT_ENABLED = true;
  7.  
  8. // Pick formation:
  9. // "circle", "polygon5", "polygon6", "star5", "star8",
  10. // "infinity", "spiral", "snowflake", "jitter",
  11. // "wave", "heart", "polygon:N"
  12. let GLOBAL_FORMATION = "infinity";
  13.  
  14.  
  15. // ======================================================
  16. // USER FOLLOWER DEFINITIONS
  17. // Each user gets their own emoji + inherits global toggles
  18. // ======================================================
  19. const userFollowers = {
  20. "nbf641": { char: "hello" },
  21. "falling23": { char: "🐍" },
  22. "guest7": { char: "⭐" }
  23. };
  24.  
  25.  
  26. // ======================================================
  27. // FORMATION MATH ENGINE
  28. // returns {x, y} offset for angle θ
  29. // ======================================================
  30. function formationOffset(theta, formationName) {
  31.  
  32. switch (formationName) {
  33.  
  34. case "circle":
  35. return { x: Math.cos(theta), y: Math.sin(theta) };
  36.  
  37. case "polygon5":
  38. return polygon(theta, 5);
  39. case "polygon6":
  40. return polygon(theta, 6);
  41.  
  42. case "star5":
  43. return star(theta, 5);
  44. case "star8":
  45. return star(theta, 8);
  46.  
  47. case "infinity":
  48. return infinity(theta);
  49.  
  50. case "spiral":
  51. return spiral(theta);
  52.  
  53. case "snowflake":
  54. return snowflake(theta);
  55.  
  56. case "jitter":
  57. return jitter(theta);
  58.  
  59. case "wave":
  60. return wave(theta);
  61.  
  62. case "heart":
  63. return heart(theta);
  64.  
  65. default:
  66. // polygon:N
  67. if (formationName.startsWith("polygon:")) {
  68. const n = parseInt(formationName.split(":")[1]);
  69. return polygon(theta, n);
  70. }
  71. return { x: Math.cos(theta), y: Math.sin(theta) };
  72. }
  73. }
  74.  
  75. // ========= SHAPE FUNCTIONS =========
  76.  
  77. function polygon(theta, sides) {
  78. // Map continuous angle onto polygon vertices
  79. const step = (Math.PI * 2) / sides;
  80. const index = Math.floor(theta / step) % sides;
  81. const angle = index * step;
  82. return { x: Math.cos(angle), y: Math.sin(angle) };
  83. }
  84.  
  85. function star(theta, points) {
  86. const inner = { r: 0.5 };
  87. const outer = { r: 1.0 };
  88. const step = Math.PI / points;
  89.  
  90. const i = Math.floor(theta / step) % (points * 2);
  91. const radius = (i % 2 === 0 ? outer.r : inner.r);
  92. const angle = i * step;
  93. return { x: Math.cos(angle) * radius, y: Math.sin(angle) * radius };
  94. }
  95.  
  96. function infinity(theta) {
  97. return { x: Math.cos(theta), y: Math.sin(theta) * Math.cos(theta) };
  98. }
  99.  
  100. function spiral(theta) {
  101. const r = 0.2 + (theta % (Math.PI * 2)) / (Math.PI * 2);
  102. return { x: Math.cos(theta) * r, y: Math.sin(theta) * r };
  103. }
  104.  
  105. function snowflake(theta) {
  106. const r = 1 + 0.3 * Math.cos(6 * theta);
  107. return { x: r * Math.cos(theta), y: r * Math.sin(theta) };
  108. }
  109.  
  110. function jitter(theta) {
  111. return {
  112. x: Math.cos(theta) + (Math.random() - 0.5) * 0.5,
  113. y: Math.sin(theta) + (Math.random() - 0.5) * 0.5
  114. };
  115. }
  116.  
  117. function wave(theta) {
  118. const r = 1 + 0.4 * Math.sin(theta * 3);
  119. return { x: Math.cos(theta) * r, y: Math.sin(theta) * r };
  120. }
  121.  
  122. function heart(theta) {
  123. // classic parametric heart curve
  124. const x = 16 * Math.pow(Math.sin(theta), 3);
  125. const y = -(13 * Math.cos(theta) - 5 * Math.cos(2 * theta)
  126. - 2 * Math.cos(3 * theta) - Math.cos(4 * theta));
  127. return { x: x / 16, y: y / 16 };
  128. }
  129.  
  130.  
  131. // ======================================================
  132. // PHYSICS FOLLOWER — fully upgraded
  133. // ======================================================
  134. function physicsLagFollower(options) {
  135. const followChar = options.char;
  136. const targetName = options.targetName;
  137.  
  138. const accel = 0.18;
  139. const friction = 0.88;
  140. const maxSpeed = 0.2;
  141. const lagDistance = 4;
  142.  
  143. const orbitRadius = 4;
  144. const orbitSpeed = 0.04;
  145. let orbitAngle = 0;
  146.  
  147. const lifetime = 10000;
  148. const startTime = performance.now();
  149. let dead = false;
  150.  
  151. let fx = 0, fy = 0;
  152. let vx = 0, vy = 0;
  153. let lx = null, ly = null;
  154. let initialized = false;
  155.  
  156. function findCursorByName(name) {
  157. for (const [key, c] of w.cursors.entries()) {
  158. if (c && c.n === name) return c;
  159. }
  160. return null;
  161. }
  162.  
  163. function clearBetween(x1, y1, x2, y2) {
  164. if (x1 === null || y1 === null) return;
  165. const minX = Math.min(x1, x2);
  166. const maxX = Math.max(x1, x2);
  167. const minY = Math.min(y1, y2);
  168. const maxY = Math.max(y1, y2);
  169. for (let y = minY; y <= maxY; y++) {
  170. for (let x = minX; x <= maxX; x++) {
  171. writeCharAt(" ", null, x, y);
  172. }
  173. }
  174. }
  175.  
  176. function kill() {
  177. if (dead) return;
  178. dead = true;
  179. if (lx !== null && ly !== null) writeCharAt(" ", null, lx, ly);
  180. }
  181.  
  182. function tick() {
  183. if (!dead && performance.now() - startTime >= lifetime) return kill();
  184. if (dead) return;
  185.  
  186. const c = findCursorByName(targetName);
  187. if (!c || !c.l) return kill();
  188.  
  189. const tx = c.l[0];
  190. const ty = c.l[1];
  191.  
  192. if (!initialized) {
  193. fx = tx;
  194. fy = ty;
  195. initialized = true;
  196. }
  197.  
  198. let targetX, targetY;
  199.  
  200. if (GLOBAL_ORBIT_ENABLED) {
  201. orbitAngle += orbitSpeed;
  202. const f = formationOffset(orbitAngle, GLOBAL_FORMATION);
  203. targetX = tx + f.x * orbitRadius;
  204. targetY = ty + f.y * orbitRadius;
  205. } else {
  206. // Physics lag fallback
  207. const dxFull = fx - tx;
  208. const dyFull = fy - ty;
  209. const dist = Math.hypot(dxFull, dyFull);
  210.  
  211. if (dist < 0.001) {
  212. targetX = tx - lagDistance;
  213. targetY = ty;
  214. } else {
  215. const nx = dxFull / dist;
  216. const ny = dyFull / dist;
  217. targetX = tx + nx * lagDistance;
  218. targetY = ty + ny * lagDistance;
  219. }
  220. }
  221.  
  222. // Physics step
  223. const dx = targetX - fx;
  224. const dy = targetY - fy;
  225.  
  226. vx += dx * accel;
  227. vy += dy * accel;
  228.  
  229. vx *= friction;
  230. vy *= friction;
  231.  
  232. const speed = Math.hypot(vx, vy);
  233. if (speed > maxSpeed) {
  234. const scale = maxSpeed / speed;
  235. vx *= scale;
  236. vy *= scale;
  237. }
  238.  
  239. fx += vx;
  240. fy += vy;
  241.  
  242. const rx = Math.round(fx);
  243. const ry = Math.round(fy);
  244.  
  245. if (rx !== lx || ry !== ly) {
  246. clearBetween(lx, ly, rx, ry);
  247. writeCharAt(followChar, null, rx, ry);
  248. lx = rx; ly = ry;
  249. }
  250.  
  251. requestAnimationFrame(tick);
  252. }
  253.  
  254. requestAnimationFrame(tick);
  255. }
  256.  
  257.  
  258. // ======================================================
  259. // SPAWN FOLLOWERS FOR ALL USERS
  260. // ======================================================
  261. Object.entries(userFollowers).forEach(([username, data]) => {
  262. physicsLagFollower({
  263. char: data.char,
  264. targetName: username
  265. });
  266. });
  267.  
Advertisement
Comments
  • smoothretro82
    247 days
    # text 0.08 KB | 0 0
    1. Update 0.1: Added: const lifetime = options.lifetime || 18000; // ms until death
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • User was banned
Add Comment
Please, Sign In to add comment