๐Ÿž️ River Distance Explorer – Learn Trigonometry Through a Fun Interactive Game

๐Ÿž️ River Distance Explorer


๐Ÿž️ River Distance Explorer – Learn Trigonometry Through a Fun Interactive Game

Are you a fan of math and visual learning? Want to see trigonometric concepts like tangent and triangle angles come to life? Look no further! ๐ŸŽฏ

Today, I’d love to introduce a simple but powerful educational game I created called River Distance Explorer. This browser-based game allows you to measure the distance across a river using a virtual triangle and your understanding of right-angle trigonometry.


๐ŸŽฎ How It Works

In this interactive canvas:

  • Points A and B are on your side of the river.

  • Point C is across the river.

  • Point B is fixed, while A can be dragged left or right.

  • A dashed arrow (AC) points from A to C.

  • You can drag the tip of the arrow (point C) to change the angle.

  • Using the angle ∠CAB and the length of AB, the game calculates BC, the distance across the river using:

    tan(ฮธ)=BCABBC=AB×tan(ฮธ)\text{tan}(\theta) = \frac{\text{BC}}{\text{AB}} \Rightarrow \text{BC} = \text{AB} \times \tan(\theta)

Not only that, you’ll also see the angle ∠CBA displayed, giving you a deeper understanding of triangle geometry.


๐Ÿ“ What You’ll Learn

This game introduces or reinforces:

  • Understanding right triangles and their angles

  • Using the tangent function to calculate unknown side lengths

  • How changing angles and lengths affect triangle measurements

  • Basic vector math to calculate angles between two lines


๐Ÿ’ป Try It Yourself – Full Source Code

Here’s the complete HTML + JavaScript code. You can copy this into an .html file and open it in any browser:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>River Distance Explorer</title>
  <style>
    body {
      text-align: center;
      font-family: Arial, sans-serif;
      background-color: #e0f7fa;
    }
    canvas {
      border: 2px solid #333;
      margin-top: 20px;
      background-color: #ffffff;
    }
    #output {
      margin-top: 15px;
      font-size: 18px;
    }
    button {
      margin-top: 10px;
      padding: 10px 20px;
      font-size: 16px;
      background-color: #0288d1;
      color: white;
      border: none;
      border-radius: 5px;
      cursor: pointer;
    }
    button:hover {
      background-color: #0277bd;
    }
  </style>
</head>
<body>
  <h1>๐Ÿž️ River Distance Explorer</h1>
  <canvas id="canvas" width="800" height="400"></canvas>
  <br>
  <button onclick="measureDistance()">๐Ÿ“ Measure Distance</button>
  <div id="output"></div>

  <script>
    const canvas = document.getElementById("canvas");
    const ctx = canvas.getContext("2d");

    const B = { x: 400, y: 300 }; // ๊ธฐ์ค€์ 
    let A = { x: 300, y: 300 };  // ์ˆ˜ํ‰ ์ด๋™์ 
    let C = { x: 400, y: 100 };  // ํ™”์‚ดํ‘œ ๋ (์‚ฌ์šฉ์ž ์กฐ์ ˆ ๊ฐ€๋Šฅ)

    let draggingA = false;
    let draggingC = false;
    let angleCBA_deg = 90;

    function drawArrow(fromX, fromY, toX, toY, color = "blue") {
      const headlen = 10;
      const angle = Math.atan2(toY - fromY, toX - fromX);
      ctx.strokeStyle = color;
      ctx.fillStyle = color;
      ctx.setLineDash([6, 4]);
      ctx.beginPath();
      ctx.moveTo(fromX, fromY);
      ctx.lineTo(toX, toY);
      ctx.stroke();
      ctx.setLineDash([]);

      // ํ™”์‚ด์ด‰
      ctx.beginPath();
      ctx.moveTo(toX, toY);
      ctx.lineTo(toX - headlen * Math.cos(angle - Math.PI / 6), toY - headlen * Math.sin(angle - Math.PI / 6));
      ctx.lineTo(toX - headlen * Math.cos(angle + Math.PI / 6), toY - headlen * Math.sin(angle + Math.PI / 6));
      ctx.lineTo(toX, toY);
      ctx.fill();
    }

    function draw() {
      ctx.clearRect(0, 0, canvas.width, canvas.height);

      // ๊ฐ•
      ctx.fillStyle = "#81d4fa";
      ctx.fillRect(0, 200, canvas.width, 50);

      // ์  A, B, C
      ctx.fillStyle = "black";
      ctx.beginPath();
      ctx.arc(A.x, A.y, 5, 0, Math.PI * 2);
      ctx.fill();
      ctx.fillText("A", A.x - 10, A.y + 20);

      ctx.beginPath();
      ctx.arc(B.x, B.y, 5, 0, Math.PI * 2);
      ctx.fill();
      ctx.fillText("B", B.x + 10, B.y + 15);
      ctx.fillText("∠CBA: " + angleCBA_deg + "°", B.x + 10, B.y - 20);

      ctx.beginPath();
      ctx.arc(C.x, C.y, 5, 0, Math.PI * 2);
      ctx.fill();
      ctx.fillText("C", C.x + 10, C.y - 10);

      // ์„  AB (๋นจ๊ฐ„์ƒ‰), BC (์ดˆ๋ก์ƒ‰)
      ctx.strokeStyle = "red";
      ctx.beginPath();
      ctx.moveTo(A.x, A.y);
      ctx.lineTo(B.x, B.y);
      ctx.stroke();

      ctx.strokeStyle = "green";
      ctx.beginPath();
      ctx.moveTo(B.x, B.y);
      ctx.lineTo(C.x, C.y);
      ctx.stroke();

      // ํ™”์‚ดํ‘œ AC
      drawArrow(A.x, A.y, C.x, C.y, "blue");
    }

    canvas.addEventListener("mousedown", (e) => {
      const rect = canvas.getBoundingClientRect();
      const x = e.clientX - rect.left;
      const y = e.clientY - rect.top;

      if (Math.abs(x - A.x) < 10 && Math.abs(y - A.y) < 10) {
        draggingA = true;
      } else if (Math.abs(x - C.x) < 10 && Math.abs(y - C.y) < 10) {
        draggingC = true;
      }
    });

    canvas.addEventListener("mouseup", () => {
      draggingA = false;
      draggingC = false;
    });

    canvas.addEventListener("mousemove", (e) => {
      const rect = canvas.getBoundingClientRect();
      const x = e.clientX - rect.left;
      const y = e.clientY - rect.top;

      const vecBC = { x: C.x - B.x, y: C.y - B.y };
      const vecBA = { x: A.x - B.x, y: A.y - B.y };
      angleCBA_deg = getAngleBetween(vecBC, vecBA).toFixed(2);

      if (draggingA) {
        A.x = x;
      } else if (draggingC) {
        C.x = x;
        C.y = y;
      }
      draw();
    });

    function measureDistance() {
      const AB = Math.abs(B.x - A.x);
      const angleCAB_rad = Math.atan2(A.y - C.y, C.x - A.x);
      const angleCAB_deg = (angleCAB_rad * 180 / Math.PI).toFixed(2);
      const BC = Math.tan(angleCAB_rad) * AB;

      const vecBC = { x: C.x - B.x, y: C.y - B.y };
      const vecBA = { x: A.x - B.x, y: A.y - B.y };
      angleCBA_deg = getAngleBetween(vecBC, vecBA).toFixed(2);

      document.getElementById("output").innerHTML = `
        <b>Angle ∠CAB:</b> ${angleCAB_deg}° <br>
        <b>Angle ∠CBA:</b> ${angleCBA_deg}° <br>
        <span style="color:red;">AB</span> = ${AB.toFixed(2)} px <br>
        <span style="color:green;">BC</span> = ${BC.toFixed(2)} px (Distance across the river) <br>
        <span style="color:blue;">Formula:</span> tan(ฮธ) = BC / AB → BC = AB × tan(ฮธ)
      `;
    }

    function getAngleBetween(v1, v2) {
      const dot = v1.x * v2.x + v1.y * v2.y;
      const mag1 = Math.sqrt(v1.x ** 2 + v1.y ** 2);
      const mag2 = Math.sqrt(v2.x ** 2 + v2.y ** 2);
      const cosTheta = dot / (mag1 * mag2);
      return Math.acos(cosTheta) * (180 / Math.PI);
    }

    draw();
  </script>
</body>
</html>

๐Ÿง  Final Thoughts

This game is a great tool for:

  • Visual learners

  • Students practicing trigonometry

  • Teachers wanting a demo for their math class

  • Anyone who loves geometry and playing with angles!

Feel free to extend it — maybe add randomized challenges, point scoring, or different terrain!


If you enjoyed this, leave a comment or let me know how you'd like to expand the game.
Happy exploring! ๐ŸŒŠ๐Ÿ“๐Ÿš€



Comments

Popular posts from this blog

๐Ÿ“ Fun Fruit Math Game for Kids – Learn Multiplication & Division with Smiles!

Visualize Permutations and Combinations with Fruits!