Game AI & Unity/L-system algorithm

[L-system] HTML 코드로 가져와보기

bay07 2024. 3. 21. 20:33
1. Rules (규칙)
 L-시스템의 규칙들을 입력. 각 규칙은 하나의 문자를 다른 문자 또는 문자열로 변환하는 규칙을 나타낸다 
ex) F->FF+[+F-F-F]-[-F+F+F]; X->F+X+F[-F-X+F]
'F'를 'FF+[+F-F-F]-[-F+F+F]'로, 'X'를 'F+X+F[-F-X+F]'로 변환한다.
여러개도 입력 가능한데, 그럴 때는 ; 로 구분한다 

2. Axiom (액시엄)
L-시스템의 초기 상태를 나타냄. L-시스템의 시작 모양을 결정한다. ex) "F"나 "X"와 같은 단일 문자열

3. Iterations (반복 횟수)
액시엄을 바탕으로 규칙을 반복적으로 적용할 횟수를 입력. 입력한 횟수만큼 액시엄에 규칙이 적용되어 새로운 문자열이 생성된다.
ex) 5, 6

4. Step Size (스텝 크기)
선을 그릴 때 한 스텝마다 이동하는 거리를 결정한다. 
예를 들어, "F" 명령에 대한 거리(스텝 크기)
ex) 10, 5

5. Angle (각도):
회전 명령에 사용되는 각도를 입력.선을 그리는 방향을 변경하는 데 사용된다.
ex) 25, 30

 

원래는 Python이나 Java로 하는 것이 더 좋지만, 웹에서 확인해보고 싶어서 HTML과 JavaScript 코드를 가져왔습니다. 여러가지 규칙을 적용한 뒤, 각각의 결과를 한번 살펴보도록 하겠습니다. 

 

1. 간단한 L-시스템 규칙
규칙: F->FF+[+F-F-F]-[-F+F+F]
초기 액시엄: F
반복 횟수: 5
스텝 크기: 10
각도: 25
  2. 좀 더 복잡한 L-시스템 규칙
규칙: F->FF+[+F-F-F]-[-F+F+F]; X->F+X+F[-F-X+F]
초기 액시엄: F
반복 횟수: 6
스텝 크기: 10
각도: 20
  3. 나무 형태의 L-시스템 규칙
규칙: F->FF+[+F-F-F]-[-F+F+F]
초기 액시엄: F
반복 횟수: 7
스텝 크기: 5
각도: 22.5
  4. 대칭적인 L-시스템 규칙
규칙: F->FF+[+F-F-F]-[-F+F+F]
초기 액시엄: F
반복 횟수: 5
스텝 크기: 12
각도: 30

 

 

 

- 전체 코드 

더보기
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>L-Systems Plant</title>
<style>
  #canvas {
    border: 1px solid black;
  }
</style>
</head>
<body>
<label for="rules">Rules:</label>
<input type="text" id="rules" placeholder="Enter rules (e.g., F->FF+[+F-F-F]-[-F+F+F])"><br>
<label for="axiom">Axiom:</label>
<input type="text" id="axiom" placeholder="Enter axiom (e.g., F)"><br>
<label for="iterations">Iterations:</label>
<input type="number" id="iterations" value="5" min="1"><br>
<label for="step">Step size:</label>
<input type="number" id="step" value="10" min="1"><br>
<label for="angle">Angle:</label>
<input type="number" id="angle" value="25" min="0" max="360"><br>
<button onclick="drawLSystem()">Draw Plant</button><br>
<canvas id="canvas" width="400" height="400"></canvas>

<script>
function derivation(axiom, rules, steps) {
  let derived = [axiom];
  for (let i = 0; i < steps; i++) {
    let nextSeq = derived[derived.length - 1];
    let nextAxiom = Array.from(nextSeq).map(char => rules[char] || char).join('');
    derived.push(nextAxiom);
  }
  return derived;
}

function drawLSystem() {
  const rulesInput = document.getElementById('rules').value.trim();
  const axiomInput = document.getElementById('axiom').value.trim();
  const iterationsInput = parseInt(document.getElementById('iterations').value);
  const stepInput = parseInt(document.getElementById('step').value);
  const angleInput = parseInt(document.getElementById('angle').value);

  const canvas = document.getElementById('canvas');
  const ctx = canvas.getContext('2d');
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  const rules = {};
  rulesInput.split(';').forEach(rule => {
    const [key, value] = rule.split('->');
    rules[key.trim()] = value.trim();
  });

  const model = derivation(axiomInput, rules, iterationsInput);

  let x = canvas.width / 2;
  let y = canvas.height;
  let angle = -Math.PI / 2;

  model[iterationsInput].split('').forEach(command => {
    if (command === 'F') {
      const x1 = x + stepInput * Math.cos(angle);
      const y1 = y + stepInput * Math.sin(angle);
      ctx.beginPath();
      ctx.moveTo(x, y);
      ctx.lineTo(x1, y1);
      ctx.stroke();
      x = x1;
      y = y1;
    } else if (command === '+') {
      angle += angleInput * Math.PI / 180;
    } else if (command === '-') {
      angle -= angleInput * Math.PI / 180;
    }
  });
}
</script>
</body>
</html>