Unity3D 2D游戏开发 官方教程。(十四)

本文详细介绍了在游戏开发中如何使用SoundManager控制音效和背景音乐的播放,包括创建SoundManager对象、编写控制脚本、修改Player、Enemy和Wall预制体的音效属性,以及实现游戏内音效的动态变化。通过调整音效和背景音乐的播放,提升了游戏的沉浸感和互动性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

十四创建音效

游戏所有的音效播放都是通过SoundManager来控制的。

14.1创建SoundManager
切换Hierarchy窗口创建Empty Object修改名称为SoundManager。给SoundManager添加2个Audio Source组件。AudioSource1来播放音效,AudioSource2来播放背景音乐。
这里写图片描述
14.2创建脚本
创建C#脚本修改名称为SoundManager.cs来控制声音的播放。代码如下:

using UnityEngine;
using System.Collections;

public class SoundManager : MonoBehaviour {
    //音效
    public AudioSource efxSource;
    //背景音乐
    public AudioSource musicSource;
    public static SoundManager instance = null;
    //音量上下线
    public float lowPitchRange = 0.95f;
    public float highPitchRange = 1.05f;

    // Use this for initialization
    void Awake () 
    {
        if(instance == null)
            instance = this;
        else if(instance != this)
            Destroy(gameObject);
        DontDestroyOnLoad(gameObject);
    }
    public void PlaySingle(AudioClip clip)
    {
        efxSource.clip = clip;
        efxSource.Play();
    }
    public void RandomizeSfx(params AudioClip[] clips)
    {
        int randomIndex = Random.Range(0,clips.Length);
        float randomPitch = Random.Range(lowPitchRange,highPitchRange);
        efxSource.pitch = randomPitch;
        efxSource.clip = clips[randomIndex];
        efxSource.Play();
    }
}

编写完成后,把SoundManager.cs附加给SoundManager对象。
修改属性:
Sound Manager(Script)/Efx Source = AudioSource1
Sound Manager(Script)/Music Source = AudioSource1
设置组件属性:
AudioSource2/Audio Clips = Project/Asserts/Sounds/scavengers_music
Play On Awak = true
Loop = true
这里写图片描述
点击运行查看效果,切换关卡的时候背景音乐并没有重新开始,这是因为DontDestroyOnLoad(gameObject)的作用。
14.3修改Player
修改Player.cs脚本程序,对主角动作增加音效。代码如下:

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class Player : MovingObject
{
    //对内墙的破坏力
    public int wallDamage = 1;
    //食物增加生命
    public int pointsPerFood = 10;
    //苏打增加生命
    public int pointsPerSoda = 20;
    //重启延迟时间
    public float restartLevelDelay = 1f;
    //Player动画
    private Animator animator;
    //当前生命值
    private int food ;

    public Text foodText;

    public AudioClip moveSound1;
    public AudioClip moveSound2;
    public AudioClip eatSound1;
    public AudioClip eatSound2;
    public AudioClip drinkSound1;
    public AudioClip drinkSound2;
    public AudioClip gameOverSound;

    protected override void Start () 
    {
        animator = GetComponent<Animator>();
        food = GameManager.instance.playerFoodPoints;
        foodText.text = "Food: "+food;
        base.Start();
    }
    void Update () 
    {
        if(!GameManager.instance.playersTurn)
            return ;
        //键盘输入,控制角色移动。
        int horizontal = 0;
        int vertical = 0 ;
        horizontal = (int)Input.GetAxisRaw("Horizontal");
        vertical = (int)Input.GetAxisRaw("Vertical");
        if(horizontal!=0)
            vertical = 0;
        if(horizontal!=0 || vertical!=0)
            AttemptMove<Wall>(horizontal,vertical);
    }
    //内置函数
    private void OnDisable()
    {
        GameManager.instance.playerFoodPoints = food;
    }
    protected override void AttemptMove<T>(int xDir,int yDir)
    {
        //没移动一次食物减少1
        food--;
        foodText.text = "Food: "+food;
        RaycastHit2D hit;
        if(Move (xDir,yDir,out hit))
        {
            SoundManager.instance.RandomizeSfx(moveSound1,moveSound2);
        }
        base.AttemptMove<T>(xDir,yDir);
        GameManager.instance.playersTurn =false;
    }
    //检查是否游戏结束
    private void CheckIfGameOver()
    {
        //当前生命低于0游戏结束
        if(food <= 0 )
        {
            SoundManager.instance.PlaySingle(gameOverSound);
            SoundManager.instance.musicSource.Stop();
            GameManager.instance.GameOver();
        }
    }
    //碰撞内墙
    protected override void OnCantMove<T>(T component)
    {
        Wall hitWall = component as Wall;
        //破坏内墙
        hitWall.DamageWall(wallDamage);
        //出发PlayerChop触发器
        animator.SetTrigger("PlayerChop");
    }
    //主角移动套exit的时候,加载下一关
    private void Restart()
    {
        Application.LoadLevel(Application.loadedLevel);
    }
    //主角被敌人攻击的时候损失生命值
    public void LoseFood(int loss)
    {
        //出发PlayerHit触发器
        animator.SetTrigger("PlayerHit");
        food -= loss;
        foodText.text = "-" + loss + "Food: "+food;
        CheckIfGameOver();
    }
    //检查碰撞,exit,food,soda
    private void OnTriggerEnter2D(Collider2D other)
    {
        //主角移动到出口
        if(other.tag == "Exit")
        {
            Invoke("Restart",restartLevelDelay);
            enabled = false;
        }
        //吃掉食物
        else if(other.tag == "Food")
        {
            food += pointsPerFood;
            foodText.text = "+" + pointsPerFood + " Food: "+food;
            SoundManager.instance.RandomizeSfx(eatSound1,eatSound2);
            other.gameObject.SetActive(false);
        }
        //喝掉苏打汽水
        else if(other.tag == "Soda")
        {
            food += pointsPerSoda;
            foodText.text = "+" + pointsPerSoda + "Food: "+food;
            SoundManager.instance.RandomizeSfx(drinkSound1,drinkSound2);
            other.gameObject.SetActive(false);
        }
    }
}

设置Player预制体/PlayerScript音效属性。
moveSound1 = Project/Asserts/Audio/ scavengers_footstep1
moveSound2 = Project/Asserts/Audio/ scavengers_footstep2
eatSound1 = Project/Asserts/Audio/ scavengers_fruit1
eatSound2 = Project/Asserts/Audio/ scavengers_fruit2
drinkSound1 = Project/Asserts/Audio/ scavengers_soda1
drinkSound2 = Project/Asserts/Audio/ scavengers_soda2
gameOverSound = Project/Asserts/Audio/scavengers_die
这里写图片描述
14.4修改Enemy
修改Enemy.cs脚本代码如下:

using UnityEngine;
using System.Collections;

public class Enemy : MovingObject {
    public int playerDemage;
    public AudioClip enemyAttack1;
    public AudioClip enemyAttack2;
    private Animator animator;
    private Transform target;
    private bool skipMove;


    // Use this for initialization
    protected override void Start () {
        GameManager.instance.AddEnemyToList(this);
        animator = GetComponent<Animator>();
        target = GameObject.FindGameObjectWithTag("Player").transform;
        base.Start();
    }

    protected override void AttemptMove<T>(int xDir,int yDir)
    {
        if(skipMove)
        {
            skipMove = false;
            return ;
        }
        base.AttemptMove<T>(xDir,yDir);
        skipMove = true;
    }
    public void EnemyMove()
    {
        int xDir = 0 ;
        int yDir = 0 ;
        if(Mathf.Abs(target.transform.position.x - transform.position.x) < float.Epsilon)
            yDir = target.transform.position.y > transform.position.y ? 1:-1;
        else
            xDir = target.transform.position.x > transform.position.x ? 1:-1;
        AttemptMove<Player>(xDir,yDir);
    }
    protected override void OnCantMove<T>(T component)
    {
        Player hitPlayer = component as Player;
        hitPlayer.LoseFood(playerDemage);
        animator.SetTrigger("EnemyAttack");
        SoundManager.instance.RandomizeSfx(enemyAttack1,enemyAttack2);
    }
} 

给预制体Enemy1和Enemy2的Enemy.cs脚本组件赋值。
修改属性:
Attack Sound1 = Project/Asserts/Audio/ scavengers_enemy1
Attack Sound2 = Project/Asserts/Audio/ scavengers_enemy2
14.5修改Wall
修改脚本Wall.cs代码如下:

using UnityEngine;
using System.Collections;

public class Wall : MonoBehaviour 
{
    public AudioClip chopSound1;
    public AudioClip chopSound2;
    public Sprite dmgSprite;
    public int hp = 4;
    private SpriteRenderer spriteRenderer;

    // Use this for initialization
    void Awake () {
        spriteRenderer = GetComponent<SpriteRenderer>();
    }

    public void DamageWall(int less)
    {
        SoundManager.instance.RandomizeSfx(chopSound1,chopSound2);
        spriteRenderer.sprite = dmgSprite;
        hp -= less;
        if(hp <= 0)
            gameObject.SetActive(false);
    }
}

给预制体Wall1到Wall2的Wall.cs脚本组件赋值。
修改属性:
ChopSound1 = Project/Asserts/Audio/scavengers_chop1
Chop Sound2 = Project/Asserts/Audio/scavengers_chop2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值