프로그래밍/JS, Node.js

[Javascript] Canvas 태양, 지구와 달 애니메이션 그리기 (Circle animation)

Lou Park 2022. 1. 11. 00:58

우리가 만들어볼 애니메이션

태양을 중심으로 지구, 지구를 중심으로 달을 움직이는 애니메이션을 만들어보았다. 코딩으로하는 애니메이션에 대해서 그동안 감이 좀없고 낮설었는데, (특히 게임 스크립팅도...) 익숙해질겸 건드려보고있는데 이거...재밌다..ㅋㅋㅋㅋㅋㅋ

 

우선 매 프레임마다 모든 요소를 다시그려주어야한다. 어렸을때 책 귀퉁이에 한장 한장마다 그려서 쭈루루룩 넘기면서 애니메이션을 만들었던것처럼, 다음장을 넘기고 그리고를 반복한다.

 

반복

윈도우가 로드되면, 루프를 시작한다. 이 루프는 일정한 프레임마다 영원히 돌면서 update()를 실행시키게 된다. 

var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');

window.onload = () => {
	loop();
}

function loop() {
	// 계속해서 애니메이션 진행 
	setInterval(update, 1000 / 20); // 20FPS 프레임 속도
}

 

지우고, 그리기

update()에서는 매번 그림을 지우고, 다시 그린다.  clearRect()로 캔버스 전체를 지우고, draw...()로 그 시점에서의 태양과 지구, 달을 그려준다.

function update() {
	// 이전에 그림을 지우고 다시 그림
	context.clearRect(0, 0, canvas.width, canvas.height);
	drawSun();
	const [earthDx, earthDy] = drawEarth();
	drawMoon(earthDx, earthDy);
}

 

지구만 이해하면 OK

 

삼각함수 포스팅에서 P(x1, y1)의 위치를 알고 싶을때 x1 = cos(θ) * r, y1 = sin(θ) * r로 정리된다고 앞서 살펴보았다.  지구의 다음 위치가 바로 P(x1, y1)이되고, 지구와 태양사이의 거리가 r이된다. 그리고 나서는 currentDegree를 증가시킴으로서 θ값을 키워 점차 돌아가게 만들 수 있다.

 

달은 지구를 중심으로 돌아야하는데, 지구의 좌표를 이미 계산했으니 그 값을 반환해서 지구의 좌표를 중심으로 달의 좌표를 계산할 수 있도록 했다.

function drawEarth() {
	var distanceFromSun = 100;

	context.beginPath();

	// 캔버스의 중간지점 + 삼각비에 길이를 곱해주면 된다. 
	var dx = (canvas.width / 2) + Math.cos(deg2Rad(currentDegree)) * distanceFromSun;
	var dy = (canvas.height / 2) + Math.sin(deg2Rad(currentDegree)) * distanceFromSun;

	var radius = 10; 

	context.arc(dx, dy, radius, 0, 2 * Math.PI);
	context.lineWidth = 5;
	context.fillStyle = "lightseagreen";
	context.fill();
	context.strokeStyle = "green";
	context.stroke();

	currentDegree++;

	// 달을 위해 지구의 현재 위치를 반환
	return [dx, dy];
}

 

 

전체 소스

<!DOCTYPE html>
<meta name="viewport" content="width=device-width,initial-scale=1">
<style>
	canvas {
		background: #111111;
	}
</style>
<body>
	<canvas id="canvas" width="500" height="320"/>
</body>
<script>
	var canvas = document.getElementById('canvas');
	var context = canvas.getContext('2d');

	var currentDegree = 0; // 태양에 대한 지구의 위치(각도)
	var currentMoonDegree = 0; // 지구에 대한 달의 위치(각도) 

	window.onload = () => {
		loop();
	}

	function loop() {
		// 계속해서 애니메이션 진행 
		setInterval(update, 1000 / 20); // 20FPS 프레임 속도
	}

	function update() {
		// 이전에 그림을 지우고 다시 그림
		context.clearRect(0, 0, canvas.width, canvas.height);
		drawSun();
		const [earthDx, earthDy] = drawEarth();
		drawMoon(earthDx, earthDy);
	}


	function drawSun() {
		context.beginPath();

		// 태양의 위치는 캔버스 중간
		var dx = canvas.width / 2;
		var dy = canvas.height / 2;
		var radius = 30;

		context.arc(dx, dy, radius, 0, 2 * Math.PI);
		context.fillStyle = "yellow"
		context.fill();
		context.lineWidth = 5;
		context.strokeStyle = "orange";
		context.stroke();
	}

	function drawEarth() {
		var distanceFromSun = 100;

		context.beginPath();

		// 캔버스의 중간지점 + 삼각비에 길이를 곱해주면 된다. 
		var dx = (canvas.width / 2) + Math.cos(deg2Rad(currentDegree)) * distanceFromSun;
		var dy = (canvas.height / 2) + Math.sin(deg2Rad(currentDegree)) * distanceFromSun;

		var radius = 10; 

		context.arc(dx, dy, radius, 0, 2 * Math.PI);
		context.lineWidth = 5;
		context.fillStyle = "lightseagreen";
		context.fill();
		context.strokeStyle = "green";
		context.stroke();

		currentDegree++;

		// 달을 위해 지구의 현재 위치를 반환
		return [dx, dy];
	}

	function drawMoon(earthDx, earthDy) {
		var distanceFromEarth = 20;

		context.beginPath();
		var dx = earthDx + Math.cos(deg2Rad(currentMoonDegree)) * distanceFromEarth;
		var dy = earthDy + Math.sin(deg2Rad(currentMoonDegree)) * distanceFromEarth;
		var radius = 3;

		context.arc(dx, dy, radius, 0, 2 * Math.PI);
		context.lineWidth = 5;
		context.strokeStyle = "white";
		context.stroke();

		// 지구의 공전속도보다 훨씬 빠르게
		currentMoonDegree += 12;
	}

	function deg2Rad(degree) {
		return Math.PI / 180 * degree; 
	}
	
</script>
</html>