Lumpy Space Princess - Adventure Time

JAVASCRIPT

Game Effect 01 - music player설정에 대해 알아보자

jongyung 2023. 4. 27. 23:23

“ 지연되는 프로젝트에 인력을 더 투입하면 오히려 더 늦어진다. ”

- Frederick Philips Brooks
Mythical Man-Month 저자
728x90

설명:

지난 번 게임효과 게시글에서는 화면 구현에 대한 설명을 했습니다.

이번에는 구현한 화면이 정말로 실행이 되어, 음악을 재생할 수 있드록 설정했습니다.

 

html 파일이 아닌, js 파일에 설정했습니다.

설명은 이 js 파일을 토대로 하겠습니다.

music.js 

const allMusic = [
    {
        name : "1. Rain on me",
        artist : "Lady Gaga(ft Ariana Grande)",
        img : "music_view01",
        audio: "music_audio01"
    }, {
        name : "2. Juicy",
        artist : "Doja Cat",
        img : "music_view02",
        audio: "music_audio02"
    }, {
        name : "3. My hair",
        artist : "Ariana Grande",
        img : "music_view03",
        audio: "music_audio03"
    }, {
        name : "4. Ungodly Hour",
        artist : "Chloe x Halle",
        img : "music_view04",
        audio: "music_audio04"
    }, {
        name : "5. Feels",
        artist : "Calvin Harris(ft. Pharrell Williams, Katy Perry, Big Sean)",
        img : "music_view05",
        audio: "music_audio05"
    }, {
        name : "6. Potion",
        artist : "Calvin Harris(ft Dua Lipa & Young Thug)",
        img : "music_view06",
        audio: "music_audio06"
    }, {
        name : "7. Circle",
        artist : "SAAY(ft Tich Hyman)",
        img : "music_view07",
        audio: "music_audio07"
    }, {
        name : "8. Truth Hurts",
        artist : "Lizzo",
        img : "music_view08",
        audio: "music_audio08"
    }, {
        name : "9. Sweetest Pie",
        artist : "Megan Thee Stallion & Dua Lipa",
        img : "music_view09",
        audio: "music_audio09"
    }, {
        name : "10. I Feel It Comming",
        artist : "The Weeknd",
        img : "music_view10",
        audio: "music_audio10"
    }        
];

음악 파일의 정보를 allMusic 이라는 변수에 저장했습니다.

보이는 것처럼 배열과 객체를 이용해서 비교적 불러오기 쉬운 형태로 저장했습니다.

변수(Variable)는 프로그래밍에서 데이터를 저장하고 참조하기 위한 이름이 할당된 메모리 공간입니다.
변수는 값을 저장할 때 사용되며, 이 값을 나중에 다시 사용할 수 있도록 합니다.
변수는 값의 종류에 따라 다양한 자료형을 가질 수 있습니다.

자바스크립트에서 변수를 생성하기 위해서는 var, let, const 키워드를 사용합니다.
var 키워드는 예전부터 사용되어왔으며, let과 const 키워드는 ECMAScript 6부터 추가되었습니다.
var 키워드는 변수의 범위(scope)가 함수 단위(function scope)입니다.
let과 const 키워드는 블록 단위(block scope)의 변수를 선언합니다.
블록 단위의 변수는 if 문, for 문, while 문, 함수 등의 중괄호({}) 안에서 선언되며, 해당 블록을 벗어나면 변수가 소멸됩니다.

예를 들어, 다음은 변수를 선언하는 예시입니다.

// 변수 선언하기
var name = "John"; // 변수의 값이 문자열인 경우
let age = 30; // 변수의 값이 숫자인 경우
const PI = 3.14; // 상수의 값은 변하지 않음

// 변수에 저장된 값 출력하기
console.log(name);
console.log(age);
console.log(PI);​

변수의 이름은 자바스크립트 식별자(identifier)의 규칙을 따라야 하며, 대소문자를 구분합니다. 
변수 이름은 알파벳, 숫자, 밑줄(_) 또는 달러 기호($)로 시작할 수 있습니다. 

하지만, 일반적으로 변수 이름은 소문자로 작성하고, 여러 단어를 포함하는 경우 카멜 케이스(camelCase) 방식으로 작성합니다.

배열(Array)과 객체(Object)는 자바스크립트에서 데이터를 구성하는 두 가지 중요한 요소입니다.

배열은 하나의 변수에 여러 개의 값을 저장할 수 있는 자료형입니다. 
이러한 값들은 인덱스(index)라는 숫자로 구분되어 있으며, 첫 번째 값은 인덱스 0으로 시작합니다. 
배열은 대괄호([])를 사용하여 생성하며, 각 값을 쉼표(,)로 구분합니다. 

예를 들어, 다음과 같은 배열을 생성할 수 있습니다.

var fruits = ["apple", "banana", "orange"];

객체는 속성(property)과 값을 연결하는 컨테이너입니다. 
속성은 이름과 값을 가지며, 이름은 문자열로 작성됩니다. 
객체는 중괄호({})를 사용하여 생성하며, 속성은 쉼표(,)로 구분합니다. 

예를 들어, 다음과 같은 객체를 생성할 수 있습니다.

var person = {
  name: "John",
  age: 30,
  address: {
    street: "123 Main St",
    city: "New York",
    state: "NY"
  }
};

배열과 객체는 모두 데이터를 저장하는데 사용되지만, 배열은 순서가 있는 값의 집합을, 객체는 이름과 값의 쌍을 저장하는데 사용됩니다. 
또한 배열의 인덱스는 반드시 숫자이며, 객체의 속성 이름은 문자열이어야 합니다.

 

js 파일에서도 script 를 작성할 수 있습니다.

다음은 선택자를 만들어서 함수식과 메서드 등을 이용하여 음악 재생 버튼들이 실행되도록 한 부분에 대한 설명입니다.

const musicWrap = document.querySelector(".music__wrap");
const musicName = musicWrap.querySelector(".music__control .title h3");
const musicArtist = musicWrap.querySelector(".music__control .title p");
const musicView = musicWrap.querySelector(".music__view .images img");
const musicAudio = musicWrap.querySelector("#main__audio");
const musicPlay = musicWrap.querySelector("#control-play");
const musicPrevBtn = musicWrap.querySelector("#control-prev");
const musicNextBtn = musicWrap.querySelector("#control-next");
const musicProgress= musicWrap.querySelector(".progress");
const musicProgressBar= musicWrap.querySelector(".progress .bar");
const musicProgressCurrent= musicWrap.querySelector(".progress .timer .current");
const musicProgressDuration= musicWrap.querySelector(".progress .timer .duration");

let musicIndex = 3; // 현재 음악 인덱스

// 음악 재생
const loadMusic = (num) => {
    musicName.innerText = allMusic[num-1].name;             //뮤직 이름
    musicArtist.innerText = allMusic[num-1].artist;         //뮤직 아티스트
    musicView.src = `img/${allMusic[num-1].img}.png`;       //뮤직 이미지
    musicView.alt = allMusic[num-1].name;                   //뮤직 이미지 alt
    musicAudio.src = `audio/${allMusic[num-1].audio}.mp3`;  //뮤직 파일
}

// 재생
const playMusic = () => {
    musicWrap.classList.add("paused");
    musicPlay.setAttribute("title", "정지");
    musicPlay.setAttribute("class", "stop");
    musicAudio.play();
}

// 정지
const pauseMusic = () => {
    musicWrap.classList.remove("paused");
    musicPlay.setAttribute("title", "재생");
    musicPlay.setAttribute("class", "play");
    musicAudio.pause();
    }

// 이전 곡 재생
const prevMusic = () => {
    musicIndex == 1 ? musicIndex = allMusic.length : musicIndex--;

    loadMusic(musicIndex);
    playMusic();
}

// 다음 곡 재생
const nextMusic = () => {
    // 1 2 3 4 5 6 7 8 9 1 2 3 4 5 ...
    // musicIndex++;
    // if(musicIndex == 9){
    //     musicIndex == 1;
    // }

    // musicIndex == 9 ? musicIndex = 1 : musicIndex++;

    musicIndex == allMusic.length ? musicIndex = 1 : musicIndex++;
    
    loadMusic(musicIndex);
    playMusic();
}

// 재생 진행바
musicAudio.addEventListener("timeupdate", e => {
    
    const currentTime = e.target.currentTime; // 현재 재생되는 시간
    const duration = e.target.duration; // 오디오의 총 길이
    let progressWidth = (currentTime/duration) * 100; // 전체 길이에서 현재 진행되는 시간을 백분위 단위로 나누면

    musicProgressBar.style.width = `${progressWidth}%`;

    // 전체 시간
    musicAudio.addEventListener("loadeddata", () => {
        let audioDuration = musicAudio.duration;
        let totalMin = Math.floor(audioDuration / 60);
        let totalSec = Math.floor(audioDuration % 60);

        if(totalSec < 10) totalSec = `0${totalSec}`;
        musicProgressDuration.innerText = `${totalMin}:${totalSec}`;
    });

    // 진행 시간
    let currentMin = Math.floor(currentTime / 60);
    let currentSec = Math.floor(currentTime % 60);

    if(currentSec < 10) currentSec = `0${currentSec}`;
    musicProgressCurrent.innerText = `${currentMin}:${currentSec}`;
});

// 진행 버튼 클릭
musicProgress.addEventListener("click", (e) => {
    let progressWidth = musicProgress.clientWidth; // 전체 진행바의 총 길이
    let clickedFoffsetX = e.offsetX; // 진행바를 기준으로 측정되는 x 좌표 값
    let songDuration = musicAudio.duration; // 오디오 전체 길이

    // 백분위로 나눈 숫자에 다시 전체 길이를 곱해서 현재 재생값으로 바꿈
    musicAudio.currentTime = (clickedFoffsetX / progressWidth) * songDuration;
});

// 플레이 버튼 클릭
musicPlay.addEventListener("click", () => {
    const isMusicPaused = musicWrap.classList.contains("paused"); // 음악 재생중
    isMusicPaused ? pauseMusic() : playMusic();
});

// 이전 곡 버튼
musicPrevBtn.addEventListener("click", () => {
    prevMusic();
});

// 다음 곡 버튼
musicNextBtn.addEventListener("click", () => {
    nextMusic();
});

window.addEventListener("load", () => {
    loadMusic(musicIndex);

    // musicAudio.play();
});

여기에 쓰인 메서드와 속성들에 대해서 설명하겠습니다.

src는 HTML 문서에서 자원(Resource)의 경로를 지정하는 속성(Attribute)입니다.
src 속성은 이미지, 오디오, 비디오, 스크립트 파일 등과 같은 외부 파일의 경로를 지정하는 데 사용됩니다.
src 속성은 주로 img 태그, script 태그, audio 태그, video 태그 등에서 사용됩니다.

예를 들어, 다음과 같은 코드는 이미지를 화면에 출력합니다.
<img src="image.jpg" alt="image">​

위 코드에서 src 속성은 "image.jpg"라는 이미지 파일의 경로를 지정합니다. 
이렇게 지정된 이미지 파일은 웹 브라우저에 의해 다운로드되어 화면에 출력됩니다.

src 속성은 일반적으로 절대 경로(absolute path) 또는 상대 경로(relative path)로 지정됩니다. 
절대 경로는 전체 경로를 지정하는 것이며, 예를 들어 "http://example.com/image.jpg"와 같이 지정됩니다.

반면, 상대 경로는 현재 파일을 기준으로 상대적인 경로를 지정하는 것이며, 예를 들어 "../images/image.jpg"와 같이 지정됩니다.

alt는 HTML 문서에서 이미지나 오디오, 비디오 등의 자원이 로드되지 못했을 때 대신 보여줄 대체 텍스트(alternative text)를 지정하는 속성(Attribute)입니다. 
alt 속성은 웹 접근성(Web Accessibility) 측면에서 매우 중요합니다. 

만약 이미지가 로드되지 않았거나 스크린 리더(Screen Reader)가 사용되는 경우, alt 속성에 지정된 대체 텍스트가 화면에 출력되어 이미지가 누락되었음을 알립니다.

alt 속성은 img 태그와 area 태그에서 사용됩니다. 

예를 들어, 다음과 같은 코드는 "image.jpg"라는 이미지 파일을 출력하고, 해당 이미지가 로드되지 않았을 때 대신 "Image not found"라는 텍스트를 출력합니다.

<img src="image.jpg" alt="Image not found">

위 코드에서 alt 속성에 "Image not found"라는 대체 텍스트가 지정되어 있습니다. 
이렇게 지정된 대체 텍스트는 이미지 파일이 로드되지 못했을 때 출력됩니다.

alt 속성은 이미지에 대한 설명이나 정보를 제공하는 경우에도 사용될 수 있습니다. 
이 경우 alt 속성에는 해당 이미지에 대한 간결하고 명확한 설명을 지정해야 합니다.

classList는 DOM API에서 제공하는 속성 중 하나로, HTML 요소의 클래스(Class) 목록을 관리하는 객체(Object)입니다. 
classList 객체는 add, remove, toggle, contains 등의 메서드(Method)를 제공하여 클래스를 추가, 제거, 전환, 확인할 수 있습니다.

classList 속성을 사용하여 HTML 요소의 클래스를 동적으로 추가, 제거 또는 변경할 수 있습니다. 예를 들어, 다음과 같은 HTML 코드가 있다고 가정해봅시다.

<div class="box"></div>

이 div 요소의 클래스를 JavaScript 코드에서 동적으로 추가하려면, 다음과 같이 classList 속성을 사용할 수 있습니다.

const div = document.querySelector('.box');
div.classList.add('red');

위 코드에서 classList 속성의 add 메서드를 사용하여 "red"라는 클래스를 div 요소에 추가합니다. 
이렇게 추가된 클래스는 CSS에서 해당 클래스를 선택자로 사용하여 스타일을 적용할 수 있습니다.

classList 객체는 remove, toggle, contains 등의 다른 메서드도 제공합니다. 
remove 메서드는 클래스를 제거하고, toggle 메서드는 클래스를 추가/제거를 전환하며, contains 메서드는 클래스가 존재하는지 확인합니다. 
이러한 메서드들을 활용하여 HTML 요소의 클래스를 동적으로 관리할 수 있습니다.

삼항 연산자(ternary operator)는 JavaScript에서 조건문을 간결하게 표현할 수 있는 연산자입니다. 
?와 : 기호로 구성되며, 조건식 ? 참일 때 값 : 거짓일 때 값과 같은 형태를 가집니다. 
즉, 조건식이 참일 때는 : 앞의 값이, 거짓일 때는 : 뒤의 값이 반환됩니다.

예를 들어, 다음과 같은 코드는 age 변수의 값에 따라 "성인" 또는 "미성년자"를 출력합니다.

const age = 20;
const message = age >= 18 ? "성인" : "미성년자";
console.log(message); // "성인"

위 코드에서 age >= 18은 조건식으로, age 변수가 18 이상일 때 참(true)을 반환합니다. 
이 조건식의 결과에 따라 message 변수에 할당되는 값이 달라집니다. 
조건식이 참일 때는 "성인"이, 거짓일 때는 "미성년자"가 message 변수에 할당됩니다.

삼항 연산자를 사용하면 if-else 문보다 더 간결하게 코드를 작성할 수 있습니다. 
하지만 조건식과 반환값이 간단한 경우에만 사용하는 것이 좋습니다. 
복잡한 조건문이나 다양한 조건에 따라 반환값이 다른 경우에는 if-else 문이 더욱 적합할 수 있습니다.

setAttribute() 메서드는 DOM API에서 제공하는 메서드 중 하나로, HTML 요소의 속성(Attribute) 값을 설정합니다. 
이 메서드는 두 개의 매개변수를 받으며, 첫 번째 매개변수는 속성 이름이고 두 번째 매개변수는 속성 값입니다. 

예를 들어, 다음과 같은 HTML 코드가 있다고 가정해봅시다.

<img src="#" alt="example image">

이 img 요소의 alt 속성 값을 JavaScript 코드에서 동적으로 변경하려면, 다음과 같이 setAttribute() 메서드를 사용할 수 있습니다.

const img = document.querySelector('img');
img.setAttribute('alt', 'new image');

위 코드에서 setAttribute() 메서드를 사용하여 img 요소의 alt 속성 값을 "new image"로 설정합니다. 이렇게 변경된 속성 값은 브라우저에서 새로고침 없이 바로 적용됩니다.

setAttribute() 메서드를 사용하여 동적으로 HTML 요소의 속성 값을 변경할 수 있습니다. 이 메서드는 HTML 요소의 모든 속성에 대해 사용할 수 있으며, getAttribute() 메서드를 사용하여 현재 속성 값을 가져올 수 있습니다.

play() 메서드는 HTML5의 <audio> 및 <video> 요소에서 제공하는 메서드 중 하나입니다. 
이 메서드는 미디어 재생을 시작합니다.

예를 들어, 다음과 같은 HTML 코드가 있다고 가정해봅시다.

<audio id="myAudio" src="audio.mp3"></audio>
<button onclick="playAudio()">재생</button>

위 코드에서 <audio> 요소의 id가 "myAudio"이고, src 속성이 "audio.mp3"인 미디어 파일을 재생할 준비가 되어 있습니다. 
이제 이 미디어 파일을 play() 메서드를 사용하여 JavaScript 코드에서 재생할 수 있습니다.

function playAudio() {
  const audio = document.getElementById("myAudio");
  audio.play();
}

위 코드에서 playAudio() 함수를 호출하면, 먼저 document.getElementById() 메서드를 사용하여 "myAudio" id를 가진 요소를 찾습니다. 
그 다음, play() 메서드를 사용하여 해당 요소에 대한 미디어 재생을 시작합니다.

play() 메서드는 또한 Promise 객체를 반환하므로, 비동기적으로 미디어 재생이 완료될 때까지 기다릴 수 있습니다. 
이를 활용하여 미디어 재생이 끝나면 다음 작업을 수행하도록 코드를 작성할 수 있습니다.

pause() 메서드는 HTML5의 <audio> 및 <video> 요소에서 제공하는 메서드 중 하나입니다. 
이 메서드는 미디어 재생을 일시 중지합니다.

예를 들어, 다음과 같은 HTML 코드가 있다고 가정해봅시다.

<audio id="myAudio" src="audio.mp3"></audio>
<button onclick="pauseAudio()">일시 중지</button>

위 코드에서 <audio> 요소의 id가 "myAudio"이고, src 속성이 "audio.mp3"인 미디어 파일이 재생 중입니다. 
이제 이 미디어 파일을 pause() 메서드를 사용하여 JavaScript 코드에서 일시 중지할 수 있습니다.

function pauseAudio() {
  const audio = document.getElementById("myAudio");
  audio.pause();
}

위 코드에서 pauseAudio() 함수를 호출하면, 먼저 document.getElementById() 메서드를 사용하여 "myAudio" id를 가진 요소를 찾습니다. 
그 다음, pause() 메서드를 사용하여 해당 요소에 대한 미디어 재생을 일시 중지합니다.

pause() 메서드는 미디어를 일시 중지할 뿐만 아니라, play() 메서드와 마찬가지로 Promise 객체를 반환하므로, 비동기적으로 미디어 일시 중지가 완료될 때까지 기다릴 수 있습니다. 
이를 활용하여 미디어 일시 중지가 완료되면 다음 작업을 수행하도록 코드를 작성할 수 있습니다.

Math.floor()는 전달된 숫자를 소수점 이하에서 가장 큰 정수로 내림한 값을 반환하는 JavaScript의 내장 함수입니다.

예를 들어, Math.floor(3.99)를 호출하면 3을 반환합니다. 
Math.floor() 함수는 양수와 음수 모두에 대해 작동합니다. 
음수의 경우, 가장 큰 정수로 내림하면 값을 더욱 작아지게 되므로, -3.1과 같은 값은 -4가 됩니다.

Math.floor() 함수는 Math.ceil() 함수와 반대되는 역할을 합니다. 
Math.ceil() 함수는 전달된 숫자를 소수점 이하에서 가장 작은 정수로 올림한 값을 반환합니다.

예를 들어, Math.floor(4.2)는 4를 반환하고, Math.ceil(4.2)는 5를 반환합니다.

이러한 내장 함수들은 JavaScript에서 수학적 계산을 쉽게 수행할 수 있도록 도와줍니다.

offsetX는 마우스 이벤트 객체에서 제공되는 속성 중 하나입니다. 
이 속성은 이벤트가 발생한 요소의 왼쪽 모서리와 이벤트가 발생한 지점 사이의 거리를 픽셀로 반환합니다.

예를 들어, 마우스 이벤트가 발생한 요소의 왼쪽 모서리에서 20픽셀 오른쪽에 마우스 커서가 위치했다면, offsetX의 값은 20이 됩니다. 
마우스 이벤트가 발생한 요소의 오른쪽 모서리를 벗어나면 음수의 값도 반환될 수 있습니다.

offsetX 속성은 주로 마우스 이벤트를 처리할 때 사용됩니다. 
이벤트가 발생한 요소 내에서 마우스 커서의 위치를 파악하는 데 유용하게 활용할 수 있습니다. 

예를 들어, 마우스 클릭 이벤트가 발생하면 offsetX와 offsetY 속성 값을 사용하여 이벤트가 발생한 요소 내에서 마우스 커서의 위치를 확인하고, 해당 위치에 대한 작업을 수행할 수 있습니다.