Article directory
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 Unity
as 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:
Running effect:
Published exe
, Running effect:
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
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,
我的电台
电台
UI
Sprite (2D and UI)
UI
3. Use UGUI to make interface
The final interface effect is as follows, and
I will pick the key points below.
1. Interface layout
Before starting to make UI
the 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
we make the interface, we will do it according to the upper, middle and lower parts,
as follows:
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:
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
2. Account circular avatar
The avatar picture is square, as follows:
We need to display a round avatar, and we can use Mask
components. The following head_frame
node
uses a 圆形
picture to display and hangs Mask
the component.
The child node head_img
is the avatar picture.
Use RawImage
the component to display the avatar.
The effect is as follows :
3. Search box
The search box uses InputField
components to
replace the picture of the box and set the color, as follows.
Put another one in the search box Button
to display the picture of the magnifying glass.
The effect is as follows:
4. Adjust the UI layer
我的音乐
This button is
correct to be displayed at the front.
The reason why it is blocked is because UGUI
the 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.
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 Canvas
component for it separately and set it to a value greater than the previous level, so Sort Order
that it can be displayed in the front normally.Canvas
Sort Order
5. Black button floating highlight effect
When the mouse hovers over the button, the button is highlighted, as follows,
if you Image
set the button image to black, then there is no such highlighting effect, because a button is made of Image
and Button
works together, Button
and components can be set in various states Color, Button
the color of the component Image
is multiplied by the color of the final button state color, if Image
you set the color to black, then the result of the multiplication is black, and you will not see the highlight effect, the
correct way is, Image
is white, Button
and Normal Color
is black, and the color of other states depends on specific needs. For example, the highlight Hightlighted Color
is gray, and the final color is set as follows:
6. Plain text button
This row of buttons is pure text buttons.
UGUI
The default button created is with a picture. Just make a small change. We create one through the menu Button
,
remove Image
the component,
and then assign the child node Text
to Button
the component Target Graphic
.
Set it up The color of each state of the button,
we Button
can adjust the response area by directly adjusting the width and height of the node~
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 asButton
a child node of the component
7. Adaptive scrolling list
The scrolling list is used ScrollView
, and
what needs to be dealt with is Content
self-adaptation. First, the list slides vertically. We hang components Content
on 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
Content
item
ContentSizeFitter
Vertical Fit
Preferred Size
item
item
Content
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
as The child node of the song title text, and the anchor point of the video icon is set as middle-right
follows, in this way, the video icon will use the right side of the text box as the reference line to calculate the relative position,
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
in the code , for example:Button
Image
Sprite
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 Slider
components,
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 Slider
a Image
component to it, and set the transparency to 0
,
adjust Slider
the height to a slightly larger value, and
adjust Background
the 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.Top
Bottom
Fill Area
Top
Bottom
4. Write code
1. Play and pause the song
In Unity
order 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 AudioListener
is 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.
AudioSource
Members need to be assigned AudioClip
, that is, to set a specific sound file. We can directly drag and drop a sound file to the AudioSource
member AudioClip
, as follows:
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
it. To pause playback, just call the AudioSource
sum Play
method 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
.AudioSource
GetSpectrumData
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 samples
an 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 Update
use 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 cubeObj
is a small box for display, let’s make a preset box, as follows:
the shader is used shader
, Unlit/Texture
and the map is a gradient color with white on the top and black on the bottom,
because this special effect is to be displayed in UI
the interface, and it is interspersed in UI
the layer , I use here RenderTexture
to solve.
First create one RenderTexture
,
and then create an independent camera EffectCamera
(remember to AudioListener
remove the component), Culling Mask
only check Water
the layer,
remember to Water
remove the main camera, and set
the special effect Layer
to Water
,
in this way, the special effect will only be EffectCamera
rendered in the camera,
we put Just RenderTexture
dragged it to EffectCamera
the camera Target Texture
, as follows,
then, audioEffect
hang AudioEffect
the script on the node, and assign the member object, as follows,
so that the special effect will be rendered RenderTexture
on it, as follows:
we use another one RawImage
to display it, and
we can adjust RawImage
the color to adjust The color of the special effect is as follows:
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.
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
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 Unity
is 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
Six, finished
Finally, I attach MY ALL
the 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
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~