U2Dアングリーバード研究ノート

# 官方文档:https://docs.unity3d.com/ScriptReference/index.html

パート1

基本操作
1.左下角Project面板中Assets下创建Image,Music,Scenes,Script四个文件夹,Packages不用管
2.在Scenes文件夹下新建几个unity场景文件,把预先备好的素材拉入Image与Music
3.选中Image下第一张图,例如BIRDS_1,右边Inspector面板中设置Sprite Mode为Multiple,点sprite Editor,在新窗口中点Slice并保存
4.回来Image文件夹下会看到BIRDS_1可以再细分许多子图并且已经自动命名
5.其他图片一样操作,至此素材导入完成
6.点击对应的Scene,把所需图片拉到左上方Hierarchy面板下,每个Scene都会自带一个Main Camera
7.在中间上方的Scene面板中摆放图片与摄像机的位置,操作方法跟小学时学的3DMAX差不多
8.点击正上方运行按钮,在正下方的Game面板中观察摄像机的映像,当然此时未设置动画
9.最后就是不断给场景中的对象在右边Inspector面板中add component,完

パート2

Inspector面板
1、可见,对象ID(对应代码),静态,Tag,Layer(新建一个层把用到的素材全部拉进去)
2、Transform是本对象的资态:世界XYZ绝对坐标,俯仰角/偏航角/翻滚角,XYZ缩放比例
3、Sprite Renderer:Sprite设置素材源,Order in Layer可以设置在本Layer中的等级,值越大越靠前显示
4、其他的Component就需要点击最下面的Add Component添加,添加脚本是直接输入脚本名确认,建议是脚本名与对象名能够对应
5、以下面的代码为例,有四个响应事件的API,还有三个局部变量,凡是设成public的变量可以在Inspector面板中直接更改他的值
//Bird.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Brid : MonoBehaviour{
    private bool isClick=false;
    public Transform rightPos;
    public float maxDis=3;
    private void OnMouseDown(){//对本对象鼠标按下左键时的事件
        isClick=true;
    }
    private void OnMouseUp(){//对本对象鼠标释放左键时的事件
        isClick=false;
    }
    private void Update(){//本对象每帧显示前的事件
        if(isClick){
            transform.position=Camera.main.ScreenToWorldPoint(Input.mousePosition);//重点!
            transform.position+=new Vector3(0,0,-Camera.main.transform.position.z);
            if(Vector3.Distance(transform.position,rightPos.position)>maxDis){
                Vector3 pos=(transform.position-rightPos.position).normalized;//方向不变长度变成1
                pos*=maxDis;//让向量乘上最大距离得到相对于基点的向量
                transform.position=pos+rightPos.position;//偏移向量+基点向量
            }
        }
    }
    private void Start(){//本对象第一帧显示前的事件
        //可以设置初始姿态什么的
    }
}
//这里要对上面的“重点”解释一下:
//屏幕按下对象有Input.mousePosition,然后转换成世界坐标得到transform.position,transform就是本对象
//2D场景平行视角摄像机默认坐标是(0,0,-10),摄像头面向Z轴正向,坐标转换后的坐标是落在摄像头所在摄影平面的!
//摄像机对用户触摸屏幕点坐标的转换时XY坐标可以正确转换,但是Z坐标会变成取摄像机的坐标,所以z坐标要减去摄像机z坐标

パート3

Rigidbody 2D:当Boty Type为Dynamic时绑定动力学(如自由落体等)引擎,例如小鸟,angular drag是滚动摩擦系数
Rigidbody 2D:当Boty Type为Kinematic时绑定不受动力学引擎,例如用户拖动小鸟时
(当然用户拖动时用Dynamic也OK,反正脚本中重设了对象坐标,但是这样释放时飞出去的速度会很大)
Rigidbody 2D:当Boty Type为Static时绑定可以作为Spring Joint 2D的Connected Rigid Body参数的值(弹簧另一端),例如树枝
Spring Joint 2D:绑定弹簧关节引擎,Connected Rigit Body参数是弹簧的另一端,Frequnecy是阻尼系数
Circle Collider 2D:绑定圆形碰撞引擎,Radius参数是响应半径
Box Collider 2D:绑定矩形碰撞引擎,Edit Collider可以设置响应边框

パート4鳥が飛び出す

private SpringJoint2D sp;
private Rigidbody2D rg;
private void Awake(){
    sp=GetComponent<SpringJoint2D>();
    rg=GetComponent<Rigidbody2D>();
}
private void OnMouseDown(){
    isClick=true;
    rg.isKinematic=true;//不受动力学控制,可以让用户自由拖动
}
private void OnMouseUp(){
    isClick=false;
    rg.isKinematic=false;//受动力学控制,计算受力改变其速度
    Invoke("Fly",0.1f);//计算受重力与弹簧力0.1秒之后执行Fly函数
}
private void Fly(){
    sp.enabled=false;//弹簧失效,注意Frequency的值是阻尼系数
}

パート5シーン

对THEME_01_THEME_1中进行slice得到地面拉到场景中
Add Componenet-Box Collider 2D-Edit Collider把碰撞框上边线往下拉一点让鸟在草上滚
新建env文件夹把THEME_01_THEME_1_0放进去,ctrl+d复制多份并在Scene面板中往右拉铺满整个场景
然后再把小草与天空放上来即可

パート6豚

//BIRDS_1_103拉进去场景并更改ID为pig
//添加Circle Collider 2D,按Edit Collider调整大小
//添加Rigidbody 2D,调整 Angular Drag为2
//添加Add Component,添加下面代码
public class Pig : MonoBehaviour{
    public float maxSpeed=5.0f;
    public float minSpeed=3.0f;
    private SpriteRenderer render;//精灵渲染类对象声明
    public Sprite hurt;
    private void Awake(){
        render=GetComponent<SpriteRenderer>();//定义对象为绑定的本对象
    }
    private void OnCollisionEnter2D(Collision2D collision){//碰撞检测
        print(collision.relativeVelocity.magnitude);
        if(collision.relativeVelocity.magnitude<minSpeed){
            return ;
        }
        else if(collision.relativeVelocity.magnitude>maxSpeed){
            Destroy(gameObject);
        }else if(collision.relativeVelocity.magnitude<maxSpeed && collision.relativeVelocity.magnitude>minSpeed){
            render.sprite=hurt;
        }
    }
}
//回到Inspector面板中调整上面三个public参数,hurt的值是BIRDS_1_104图片

パート7パチンコ

//左树枝left_branch加Line Renderer并设材质,在其下创建空对象并更名为leftPos
//右树枝right_branch加Line Renderer并设材质,在其下创建空对象并更名为rightPos(前面画弹簧建了可跳过)
//在Bird类中加入四个public成员,并在Inspector面板中拖动赋值
public LineRenderer right;//这四变量是树枝对象的子类对象,要在Inspector面板中赋值
public LineRenderer left;
public Transform leftPos;
public Transform rightPos;
//在update函数处加入四行代码
right.SetPosition(0,rightPos.position);
right.SetPosition(1,transform.position);
left.SetPosition(0,leftPos.position);
left.SetPosition(1,transform.position);

パート8死亡の影響

拖死亡动画第一帧到场景,重命名为Boom
增加Boom.cs脚本
public class Boom : MonoBehaviour{
    public void destroying(){
        Destroy(gameObject);
    }
}
增加Animator,ctrl+6打开动画编缉器,按create创建一个动画,放到Assets下的Animation下(无就新建)
依次拖入关键帧,并在最后一帧添加事件destroying,把场景中的Boom拖动到Assets下的prefabs下(无就新建)
在Pig.cs中,猪destroy函数后加上Instantiate(boom,transform.position,Quaternion.identity);
类成员中加上public GameObject boom;,回到Inspector面板把prefabs下的Boom拉到脚本赋值处

パート9スコアの特殊効果

拖分数到场景重命名为pigScore,再拖动到prefabs下,在Pig.cs中,在上面给死亡动画Instantiate下再写:
GameObject go=Instantiate(score,transform.position+new Vector3(0,0.8f,0),Quaternion.identity);
Destroy(go,1.5f);
在声明类成员变量时写public GameObject score;,回到Inspector面板把prefabs下的pigScore拉到脚本赋值处

パート10ゲーム管理(重くて難しい点)

//创建新的空类GameManager,往GameManager.cs中写入
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour{
    public List<Bird> birds;
    public List<Pig> pigs;
    public static GameManager _instance;
    private void Awake(){
        _instance=this;
    }
    private void Start(){
        Initialized();
    }
    private void Initialized(){
        for(int i=0;i<birds.Count;i++){
            if(i==0){
                birds[i].enabled=true;
                birds[i].sp.enabled=true;
                //birds[i].cc.enabled=true;
            }else{
                birds[i].enabled=false;
                birds[i].sp.enabled=false;
                //birds[i].cc.enabled=false;
            }
        }
    }
    public void NextBird(){
        if(pigs.Count>0){
            if(birds.Count>0){
                Initialized();
            }else{
                print("lose"); 
            }
        }else{
            print("win");
        }
    }
}
//往inspector面板中按顺便拖入鸟与猪
//Bird.cs中设置在Fly()后触发Next()唤醒下一只鸟
private void Fly(){
    sp.enabled=false;//弹簧失效,注意Frequency的值是阻尼系数
    Invoke("Next",5);
}
private void Next(){
    GameManager._instance.birds.Remove(this);
    Destroy(gameObject);
    Instantiate(boom,transform.position,Quaternion.identity);
    GameManager._instance.NextBird();
}
//至此游戏主体实现完成!!!

ツリーのパート11

GameManager.cs的Awake中加上originPos=birds[0].transform.position;
GameManager.cs的Initialized中加上birds[0].transform.position=originPos;
Bird.cs的OnMouseUp末加上right.enabled=false;left.enabled=false;

パート12パチンコ

Bird.cs的Update中SetPosition前加上right.enabled=true;left.enabled=true;

パート13木製ブロック

1. 插入多种木块图
2. 创建Rigidbody 2D使用物理学引擎如自由落体
3. 创建Box Collider 2D使用盒式碰撞引擎
4. 使用pid脚本并赋hurt/score/ispid参数
5. copy多份

パート14勝敗インターフェース

在Hierarchy界面下创建UI-Image重命名为lose,是全屏黑,不透明度一半
在lose下创建UI-Image重命名为menu,是左1/3屏黑,不透明度0
在menu创建UI-Image重命名为retry,插图是重玩按扭图片
在menu创建UI-Image重命名为exit,插图是退出按扭图片
(千万不要拉到prefabs下!)
在Hierarchy界面下创建UI-Image重命名为win,是全屏黑,不透明度一半
在lose下创建UI-Image重命名为menu,是左1/3屏黑,不透明度0
在menu创建UI-Image重命名为next,插图是下一关按扭图片
在menu创建UI-Image重命名为exit,插图是退出按扭图片
(千万不要拉到prefabs下!)
修改GameManager.cs
声明变量public GameObject Win;并把lose拉过来属性面板赋值
声明变量public GameObject Loss;并把lose拉过来属性面板赋值
在输出失败后加上Loss.SetActive(true);
在输出成功后加上Win.SetActive(true);
(补充说明下layer与sorting layer:)
sorting layer用于渲染,Unity渲染关系层级顺序:Camera -> sorting layer -> sorting order
layer用于碰撞检测,光线投射

パート15ボタンイベント(再生/次のレベル/終了)

File-Build Setting-把全部unity场景文件拉上去
在GameManager.cs中写三个函数
public void Next(){SceneManager.LoadScene(3);}
public void Replay(){SceneManager.LoadScene(2);}
public void Home(){SceneManager.LoadScene(1);}
给三个按钮Add Component-OnClick,把GameManager拉过来,再选对应的函数

パート16カメラフォロー

改摄像机的x坐标,涉及的接口:
static function Lerp (from : Vector3, to : Vector3, t : float) : Vector3 
---->返回值=from+(to-from)*t
Mathf.Clamp(float value,float min,float max)
---->在 Mathf.Clamp 中传入三个参数:value,min,max,限制 value的值在min,max之间,如果value大于max,则返回max,如果value小于min,则返回min,否者返回value;
Time.deltaTime
---->每帧间隔时间,如20帧每秒,即0.05秒/帧,则Time.deltaTime=0.05
写法一:Camera.main.transform.position=new Vector3(Mathf.Clamp(posX,0,15),Camera.main.transform.position.y,Camera.main.transform.position.z);
缺点:跟随可以实现,但是换鸟是会突然转变
写法二:float posX=transform.position.x;
Camera.main.transform.position=Vector3.Lerp(Camera.main.transform.position,\
                                            new Vector3(Mathf.Clamp(posX,0,15),\
                                                        Camera.main.transform.position.y,\
                                                        Camera.main.transform.position.z),\
                                            3*Time.deltaTime);
这个函数的意义:相机初始坐标0,0,-10,小鸟坐标的x在大于0时,返回值=from+(to-from)*t!=from产生跟随,且t是3*Time.deltaTime小于1所以不是即时跟随,平滑换鸟
3这个值的意义是1秒移动3米,太小的话相机跟不上,太大的话换鸟时会突然变化镜头位置,要自己调参得出

パート17音楽の読み込み

public AudioClip birdCollision;
if(collision.gameObject.tag=="Player")AudioSource.PlayClipAtPoint(birdCollision,transform.position);

パート18黄色い鳥

//换贴图
//写脚本Bird_yellow.cs继承
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bird_yellow : Bird{
    private bool fly_again;
    private new void Awake(){
        base.Awake();
        fly_again=false;
    }
    private new void OnMouseDown(){
        if(isFlying){
            if(!fly_again){
                rg.velocity*=2;
                fly_again=true;
            }
            return ;
        }
        if(!isClick)AudioSource.PlayClipAtPoint(select,transform.position);
        isClick=true;
        rg.isKinematic=true;
    }
}
//在面板重新赋值,GameManager也要赋
//测试参数

パート19グリーンバード

//换贴图
//写脚本Bird_green.cs继承
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bird_green : Bird{
    private bool fly_again;
    private new void Awake(){
        base.Awake();
        fly_again=false;
    }
    private new void OnMouseDown(){
        if(isFlying){
            if(!fly_again){
                Vector3 speed=rg.velocity;
                speed.x*=-1;
                rg.velocity=speed;
                fly_again=true;
            }
            return ;
        }
        if(!isClick)AudioSource.PlayClipAtPoint(select,transform.position);
        isClick=true;
        rg.isKinematic=true;
    }
}

//在面板重新赋值,GameManager也要赋
//测试参数

パート20スタートメニュー

シーンを開く:背景画像を挿入し、UIボタンを挿入し(ゲームボタンを入力してゲームボタンを終了)、以下に説明する2つのメソッドをバインドし、
GameManagerオブジェクトを作成し、GameManager.csを作成します。

public class StartMenuManager : MonoBehaviour{
    public void Enter(){
        //print("enter");
        UnityEngine.SceneManagement.SceneManager.LoadScene(1);
    }
    public void Exit(){
        //print("exit");
        #if UNITY_EDITOR
            UnityEditor.EditorApplication.isPlaying = false;
        #else
            Application.Quit();
        #endif
    }
}

パート21レベルメニュー

レベルシーン:背景画像、レベル1ボタン画像、レベル2ボタン画像、レベル2ボタン画像、戻るボタン画像
を挿入します。Colliderメソッドを追加し(BoxまたはCircleで問題ありません)、OnMouseDown()に応答するクラスを作成することを忘れないでください
例としてLevelPageExitを使用:

public class LevelPageExit : MonoBehaviour{
    public void OnMouseDown(){
        UnityEngine.SceneManagement.SceneManager.LoadScene(0);
    }
}

メモを整理する

  1. 属性インスペクターパネル
    各オブジェクトのシーン姿勢の変換は
    スプライトレンダラーマップオブジェクトは
    サークルコライダー2D円形衝突検出
    ボックスコライダー2D衝突検出長方形
    リジッドボディ2Dリジッドボディエンジン
    (静的は静止、スプリングのもう一方の端
    木の枝など))(動的質量、滑り摩擦係数、転がり摩擦係数、重力加速度などの
    力分析がありますが、コライダー衝突は含まれません)(キネマティックには力分析がなく、ユーザーの指のドラッグなどの変換によってのみ操作できます。 )
    スプリングジョイント2Dスプリングエンジン
    スプリングのもう一方の端がリジッドボディ属性の場合)
    スクリプトによって記述されたスクリプト
    ラインレンダラー線形レンダリング

  2. 他の人と自分の座標を取得する自分
    の座標:transform.positionは、実際には、これを省略します。つまり、自分の座標を省略します。publicList
    birds ;;
    private Vector3 originPos;
    originPos = birds [0] .transform.position;


  3. Bird.csの他のオブジェクトのエンジンを切り替えます
    [HideInInspector]
    public SpringJoint2D sp;
    private void Awake(){sp = GetComponent();}
    in GameManager.cs
    public List birds;
    birds [i] .enabled = true; // i鳥のBird.csスクリプトが有効になります
    birds [i] .sp.enabled = true; // i鳥のSpringJoint2Dプロパティが有効になります
    birds [i] .enabled = false; // i鳥のBird.csスクリプトが無効です
    birds [i] .sp.enabled = false; // i番目の鳥のSpringJoint2D属性が無効です

  4. 独自の物理エンジンを切り替えます(bird.csを参照)
    private Rigidbody2D rg; // default Dynamic
    private void Awake(){rg = GetComponent();}
    rg.isKinematic = true; //ダイナミクスによって制御されないため、ユーザーは自由にドラッグするには
    Dynamicrg.isKinematic = false; //ダイナミクスの制御下で、速度を変更する力を計算します

  5. 衝突検出と相対速度の
    取得(pig.csを参照)private void OnCollisionEnter2D(Collision2Dcollision){print(collision.relativeVelocity.magnitude);}

  6. 独自のテクスチャを変更します(pig.csを参照)
    public Sprite hurt; // hurt手動でパネルに
    privateSpriteRendererレンダー渡します;
    private void Awake(){render = GetComponent();}
    render.sprite = hurt;
    必要に応じて外部で変更するにはテクスチャについては、ポイント3を参照してください。

  7. アニメーション制作(boom.csを参照)
    フレームをシーン
    ctrl + 6にドラッグして、Animationフォルダーにアニメーションを作成します。
    このオブジェクトのスクリプト
    記述して、自己破壊などのトリガーイベントをキーフレームに追加します。publicvoiddestroying
    ( ){Destroy(gameObject);}
    オブジェクトをPrefabsフォルダーにドラッグすると、シーンオブジェクトが無効に設定されます

  8. 他のオブジェクトを作成および破棄します(pig.csを参照)
    public GameObject boom; //ブームはパネルで
    Instantiate(boom、transform.position、Quaternion.identity)を手動で渡します; //爆発的な
    パブリックGameObjectスコアを所定の位置に生成します; / /スコアはパネルで
    GameObjectを手動で渡しますgo = Instantiate(score、transform.position + new Vector3(0,0.8f、0)、Quaternion.identity); //
    Destroy(go、1.5f); //1.5秒投稿-破壊

  9. ボタンジャンプ(GameManager.csを参照)
    シーンにUIイメージを作成し、
    Buttonイベントを
    バインドし、GameManagerオブジェクトを
    バインドし、対応するイベントをバインドしますpublic void Replay(){SceneManager.LoadScene(scene ID);}

  10. 音乐頂放p​​ublicAudioClip
    birdCollision;
    if(collision.gameObject.tag ==“ Player”)AudioSource.PlayClipAtPoint(birdCollision、transform.position);

  11. オブジェクト指向
    カプセル化:
    国民が自由にアクセスすることができ、インスペクタパネルに渡されたパラメータを含む、サブクラスのオブジェクトが継承することができ
    、自分がアクセスすることができ、保護、サブクラスのオブジェクトが継承することができ、インスペクタパネルに表示されることはありません
    プライベートサブクラスではなく、自分でアクセスできますオブジェクト継承はインスペクターパネルに表示されません
    継承:
    黄色の鳥と緑の鳥から派生した基本的な赤い鳥(追加のスキル)
    多態性:
    各シーンのGameManagerは、維持するためにリストを使用する必要があります赤い鳥、黄色の鳥、緑の鳥を含むすべての鳥、リスト要素が基本クラスの鳥であることを宣言できます

  12. イベントをクリックします
    メソッド1:画像をプルし、衝突プロパティを追加し(必須!)、クラスをカスタマイズしてOnMouseDown()メソッドを実装し
    ますメソッド2:UI-Imageを作成し、テクスチャを割り当て、Buttonプロパティを追加し、シーンマネージャーオブジェクトにプルします(それぞれをバインドします)ボタンメソッドがクラスに実装されています)、対応するメソッドを選択します


Edit-Preference-GICacheでキャッシュパスを変更することを忘れないでください

おすすめ

転載: blog.csdn.net/cj1064789374/article/details/114626769