[Game Development Innovation] Teach you to use Unity to make a high imitation Kugou music player, Ayumi Hamasaki, Melody, Ye Qinghui (Sound Visualization | Spectrum | Audio)

I. Introduction

Hi everyone, I'm new.
The thing is like this, I heard Ayumi Hamasaki when I was listening to the song MY ALL, tears filled my eyes, the melody started, Ye Qinghui,

[4K collection-level image quality] Ayumi Hamasaki's Divine Comedy "My All" sang and cried the audience! ! !

I clicked on Kugou, took a closer look, and came up with an idea, can I use it Unityas a high-quality imitation Kugou music player, and only play this song by Ayumi Hamasaki.
So, I made one, and the final effect is as follows:
Please add a picture description
Running effect:
Please add a picture description
Please add a picture description
Published exe, Running effect:
Please add a picture description
Next, let me talk about my production process~

2. Get UI material

The following is the really cool dog interface. According to the interface, go to the Ali icon library to search for
insert image description here
the required materials. The address
of the Ali icon library: https://www.iconfont.cn/ Search and find an icon with a similar shape, as follows Click on the icon, you can first set the color of the icon to white, and then download it, and so on , the materials I am looking for are as follows: all the material picture formats are set to Jiugong grid, otherwise it may be deformed, such as this oval button,

insert image description here
我的电台
insert image description here
电台
insert image description here

insert image description here

insert image description here
UISprite (2D and UI)
insert image description here
UI
insert image description here

3. Use UGUI to make interface

The final interface effect is as follows, and
insert image description here
I will pick the key points below.

1. Interface layout

Before starting to make UIthe interface, we need to analyze the layout of the interface first. First, from the perspective of the large layout, it is upper, middle and lower. When
insert image description here
we make the interface, we will do it according to the upper, middle and lower parts,
insert image description here
as follows:
Please add a picture description
middle layout It can be further divided into the top tab bar and the bottom detail panel. Taking the example as an 我的音乐example, the bottom panel can be divided into left and right layouts, as follows:
insert image description here
In this way, we can divide the middle into three parts tabs, left, , as follows: and so on, in the large layout Embed small layouts, continue to embed small layouts in small layouts, and design reasonably according to the interface.right
insert image description here

Please add a picture description

2. Account circular avatar

The avatar picture is square, as follows:
Please add a picture description
We need to display a round avatar, and we can use Maskcomponents. The following head_framenode
insert image description here
uses a 圆形picture to display and hangs Maskthe component.
insert image description here
The child node head_imgis the avatar picture.
insert image description here
Use RawImagethe component to display the avatar.
insert image description here
The effect is as follows :
insert image description here

3. Search box

The search box uses InputFieldcomponents to
insert image description here
replace the picture of the box and set the color, as follows.
insert image description here
Put another one in the search box Buttonto display the picture of the magnifying glass.
insert image description here
insert image description here
The effect is as follows:
Please add a picture description

4. Adjust the UI layer

我的音乐This button is
insert image description here
correct to be displayed at the front.
insert image description here
The reason why it is blocked is because UGUIthe default is to render in the order of nodes, and the buttons behind it are arranged below it, so the buttons behind it will cover it.
insert image description here
If we don’t want to adjust The order of the nodes, but we want 我的音乐the button to be displayed in the front. We can hang a Canvascomponent for it separately and set it to a value greater than the previous level, so Sort Orderthat it can be displayed in the front normally.CanvasSort Order
insert image description here

insert image description here

5. Black button floating highlight effect

When the mouse hovers over the button, the button is highlighted, as follows,
Please add a picture description
if you Imageset the button image to black, then there is no such highlighting effect, because a button is made of Imageand Buttonworks together, Buttonand components can be set in various states Color, Buttonthe color of the component Imageis multiplied by the color of the final button state color, if Imageyou set the color to black, then the result of the multiplication is black, and you will not see the highlight effect, the
insert image description here
correct way is, Imageis white, Buttonand Normal Coloris black, and the color of other states depends on specific needs. For example, the highlight Hightlighted Coloris gray, and the final color is set as follows:
insert image description here

6. Plain text button

This row of buttons is pure text buttons.
insert image description here
UGUIThe default button created is with a picture. Just make a small change. We create one through the menu Button,
insert image description here
remove Imagethe component,
insert image description here
and then assign the child node Textto Buttonthe component Target Graphic.
insert image description here
Set it up The color of each state of the button,
insert image description here
we Buttoncan adjust the response area by directly adjusting the width and height of the node~
insert image description here
When the mouse is close to the text, the button can be detected, as follows,

Note: For buttons with pictures, if you also want to expand the response area of ​​the button but do not want to expand the picture itself, you can also use this to display 技巧the button background image as Buttona child node of the component

Please add a picture description

7. Adaptive scrolling list

The scrolling list is used ScrollView, and
Please add a picture description
what needs to be dealt with is Contentself-adaptation. First, the list slides vertically. We hang components Contenton the nodes , so that the height increases with the number of lists . We can use components to set the For , and then set a height, so that when the number increases, the node will automatically expand the height,VerticalLayoutGroup
insert image description here
ContentitemContentSizeFitterVertical FitPreferred Size
insert image description here
item
insert image description here
itemContent
Please add a picture description

8. Mixed arrangement of song title and video icon

In the single list, the song title and the video icon are mixed together, the video icon needs to follow the song title, the text of the song title increases, and the video icon needs to move backward automatically, as follows: this uses the anchor point, and the video icon is used
Please add a picture description
as The child node of the song title text, and the anchor point of the video icon is set as middle-rightfollows, in this way, the video icon will use the right side of the text box as the reference line to calculate the relative position,
insert image description here

9. Click the button to switch pictures

Click the button to switch the button picture, as follows Here you need to write some code, and replace the object of the component
Please add a picture description
in the code , for example:ButtonImageSprite

playBtn.onClick.AddListener(() =>
{
    
    
    if (!audioSource.isPlaying)
    {
    
    
        audioSource.Play();
        playBtn.image.sprite = pauseSprite;
    }
    else
    {
    
    
        audioSource.Pause();
        playBtn.image.sprite = playSprite;
    }
});

10. Progress bar

The progress bar uses Slidercomponents,
Please add a picture description

What needs to be solved is to expand the operating area of ​​​​the progress bar when the progress bar is very thin. The solution is to add Slidera Imagecomponent to it, and set the transparency to 0,
insert image description here
adjust Sliderthe height to a slightly larger value, and
insert image description here
adjust Backgroundthe sum to make it become Thin, in the same way, also adjust the and to make it thinner, so that the progress bar can be very thin, but the operating area is guaranteed.TopBottom
insert image description here
Fill AreaTopBottom
insert image description here

insert image description here

4. Write code

1. Play and pause the song

In Unityorder to play a sound and hear it, two components are needed, one is AudioSource(equivalent to a speaker) and the other AudioListener(equivalent to an ear),
which AudioListeneris hung on the camera by default. If you have multiple cameras, make sure that the scene There is only one active state AudioListener, otherwise an error will be reported.
AudioSourceMembers need to be assigned AudioClip, that is, to set a specific sound file. We can directly drag and drop a sound file to the AudioSourcemember AudioClip, as follows:
insert image description here
We can also dynamically set it in the code:

// AudioClip audioClip = TODO 动态加载AudioClip文件;
audioSource.clip = audioClip;


Dynamically loading resource files I have talked about three main methods in my previous article. If you are interested, you can read
insert image description here
it. To pause playback, just call the AudioSourcesum Playmethod Pause:

// (继续)播放
audioSource.Play();
// 暂停
audioSource.Pause();

2. Sound spectrum effects

During sound playback, spectrum effects can be displayed in real time. The interface to be used here can sample sound spectrum data blocks
Please add a picture description
.AudioSourceGetSpectrumData

public static void GetSpectrumData(float[] samples, 
									int channel, 
									FFTWindow window);

Parameter description:
samples: The return value of the function. Transfer the audio sample data to samplesan array, the size of the array must be 2的n次方min 64, max 8192.
channel: channel, generally set to 0.
window: The window function used to convert the signal. The more complex the algorithm, the softer the sound, but the slower the speed.
Usage:
First declare a floating-point array:

public float[] samples = new float[512];

Then Updateuse the method inside the method:

audiosource.GetSpectrumData(samples, 0, FFTWindow.BlackmanHarris);

I have encapsulated a script here, as follows:

using UnityEngine;

/// <summary>
/// 声音特效
/// </summary>
public class AudioEffect : MonoBehaviour
{
    
    
    // 用于显示的方块
    public GameObject cubeObj;
    // 方块的其实点
    public Transform startPoint;

    // 采样数据长度
    private const int SPECTRUM_CNT = 512;
    // 采样数据
    private float[] spectrumData = new float[SPECTRUM_CNT];
    // 方块Transform数组
    private Transform[] cubeTransforms = new Transform[SPECTRUM_CNT];

    void Start()
    {
    
    
        //cube生成与排列
        Vector3 p = startPoint.position;

        for (int i = 0; i < SPECTRUM_CNT; i++)
        {
    
    
            p = new Vector3(p.x + 0.11f, p.y, p.z);
            GameObject cube = Instantiate(cubeObj, p, cubeObj.transform.rotation);
            cube.transform.parent = startPoint;
            cubeTransforms[i] = cube.transform;
        }
    }

    /// <summary>
    /// 当前帧频率波功率,传到对应cube的localScale
    /// </summary>
    public void UpdateEffect(AudioSource audioSource)
    {
    
    
        audioSource.GetSpectrumData(spectrumData, 0, FFTWindow.BlackmanHarris);
        float scaleY;
        for (int i = 0; i < SPECTRUM_CNT; i++)
        {
    
    
            scaleY = Mathf.Lerp(cubeTransforms[i].localScale.y, spectrumData[i] * 10000f, 0.5f);
            // 限制一下功率
            if (scaleY > 400)
            {
    
    
                scaleY -= 400;
            }
            else if (scaleY > 300)
            {
    
    
                scaleY -= 300;
            }
            else if (scaleY > 200)
            {
    
    
                scaleY -= 200;
            }
            else if (scaleY > 100)
            {
    
    
                scaleY -= 100;
            }

            cubeTransforms[i].localScale = new Vector3(0.15f, scaleY, 0.15f);
        }
    }
}

Among them cubeObjis a small box for display, let’s make a preset box, as follows:
insert image description here
the shader is used shader, Unlit/Textureand the map is a gradient color with white on the top and black on the bottom,
insert image description here
because this special effect is to be displayed in UIthe interface, and it is interspersed in UIthe layer , I use here RenderTextureto solve.
First create one RenderTexture,
insert image description here
and then create an independent camera EffectCamera(remember to AudioListenerremove the component), Culling Maskonly check Waterthe layer,
insert image description here
remember to Waterremove the main camera, and set
insert image description here
the special effect Layerto Water,
insert image description here
in this way, the special effect will only be EffectCamerarendered in the camera,
we put Just RenderTexturedragged it to EffectCamerathe camera Target Texture, as follows,
insert image description here
then, audioEffecthang AudioEffectthe script on the node, and assign the member object, as follows,
insert image description here
so that the special effect will be rendered RenderTextureon it, as follows:
Please add a picture description
we use another one RawImageto display it, and
insert image description here
we can adjust RawImagethe color to adjust The color of the special effect is as follows:
Please add a picture description

4. Get the total duration of the sound

var len = audioSource.clip.length;

5. Set the current timestamp

Set the current timestamp according to the progress of the progress bar

slider.onValueChanged.AddListener((v) =>
    {
    
    
        if (v < 1)
            audioSource.time = v * audioSource.clip.length;
    });

6. Release the exe to hide the title bar

After publishing exe, the default title bar is automatically hidden when running.
Please add a picture description
I have written related articles before, "Unity releases window patterns for PC platform exe (Windows API, capture close events, hide window title bar, hide minimized Maximize the close button, etc.)"
used a few Windows API, as follows:

[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();

[DllImport("user32.dll")]
public static extern long GetWindowLong(IntPtr hwd, int nIndex);

[DllImport("user32.dll")]
public static extern void SetWindowLong(IntPtr hwd, int nIndex, long dwNewLong);

[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hwd, int cmdShow);

Hide title bar:

#if UNITY_STANDALONE && !UNITY_EDITOR
/// <summary>
/// 窗口风格
/// </summary>
const int GWL_STYLE = -16;
/// <summary>
/// 标题栏
/// </summary>
const int WS_CAPTION = 0x00c00000;


// 隐藏标题栏
var hwd = GetForegroundWindow();
var wl = GetWindowLong(hwd, GWL_STYLE);
wl &= ~WS_CAPTION;
SetWindowLong(hwd, GWL_STYLE, wl);
#endif

In addition, we need to implement the logic of these three buttons to
insert image description here
minimize the window:

#if UNITY_STANDALONE && !UNITY_EDITOR
/// <summary>
/// 最小化
/// </summary>
const int SW_SHOWMINIMIZED = 2;

// 获得窗口句柄
var hwd = GetForegroundWindow();
// 设置窗口最小化
ShowWindow(hwd, SW_SHOWMINIMIZED);
#endif

Maximize the window:

#if UNITY_STANDALONE && !UNITY_EDITOR
/// <summary>
/// 最大化
/// </summary>
const int SW_SHOWMAXIMIZED = 3;

// 获得窗口句柄
var hwd = GetForegroundWindow();
// 设置窗口最小化
ShowWindow(hwd, SW_SHOWMAXIMIZED);
#endif

turn off an app:

Application.Quit();

5. Project source code

I uploaded the project source code of this article CODE CHINA. Interested students can download and learn by themselves.
Address: https://codechina.csdn.net/linxinfa/UnityMusicPlayer
Note: The version I am using Unityis Unity 2020.1.14f1c1 (64-bit),
warm reminder: this project is for learning use only , it is forbidden to use for commercial purposes, otherwise the consequences will be at your own risk
insert image description here

Six, finished

Finally, I attach MY ALLthe lyrics of Ayumi Hamasaki. I don’t know the meaning of the song when I first know it, but after listening to it, I am already in the song!

How many times
have we traveled together
How many journeys have
we traveled together What
we have left so far
Although it is not perfect, it has also been brilliant
Now those crystals here
are shining with pride
I have always been so happy and happy
Frankly speaking, that is not the case
But we I'll never
be alone
I want you to see where your dreams are There
's no end and no death
I really want to see that dream
That's what I want I
want to always be by your side
No matter what happens
I'll use my all
I have always guarded you
and never regretted it.
Knowing now, I can say this.
We have always tried our best
to fight to the end.
In those unforgettable nights , we
will often think of you.
However, we
will never be alone.
Seeing your smile makes me
feel It's blinding to be in love, I
want to see that smile again
, so I still live to this day,
I can feel your love,
powerful and warm,
such a free love,
I feel it with all my strength, I
want you to see where your dreams are, there
is no end, no death
I really want you to see that dream
That's my wish
I want to be by your side
No matter what happens, I will always protect you
with all I have

Please add a picture description
Alright, let’s stop here, I’m going to listen to the Yibian series again~
I’m Lin Xinfa: https://blog.csdn.net/linxinfa
It’s not easy to be original, if you repost, please indicate the source, thank you everyone~
I like me If you have any technical questions, please leave a message or private message, and we will see you next time~

Guess you like

Origin blog.csdn.net/linxinfa/article/details/119912971