【Unity 2D游戏开发教程】哔哩哔哩_bilibili

快捷键 作用
shift + 空格 局部工作区全屏、恢复
鼠标滚轮滚动 场景放大缩小
鼠标滚轮按住 变成小手,类似ps
鼠标右键 移动视角(旋转)
在场景中选中某个object按delete 删除
ctrl + D 复制对象
1
2
3
4
5
6
7
├─Assets    
├─Animations
├─Materials
├─Prefabs
├─Scripts
├─Sences
└─Sprites

添加组件rect修改锚定点

组件:

Rigidbody 2D钢体

void FixedUpdate()

Input.GetAxisRaw(“Horizontal”); -1, 0, 1

Input.GetAxis(“Horizontal”); 平滑变化

【Unity 2D游戏开发教程】

第1课 如何在Unity中快速导入序列帧动画 Aseprite动画帧导出

切割

画像素动画的软件Aseprite

多张图片拖入会被识别为动画

第2课 如何在Unity中实现Player左右移动 2D Movement

加钢体Rigidbody 2D:碰撞检测改为连续检测,睡眠模式改成不睡眠,忽略z轴

加Capsule Collider 2D:

加Box Collider 2D:设置为可触发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerContraller : MonoBehaviour
{
public float runSpeed;
private Rigidbody2D myRigidbody;
// Start is called before the first frame update
void Start()
{
// 获取组件
myRigidbody = GetComponent<Rigidbody2D>();
}

// Update is called once per frame
void Update()
{
Run();
}

void Run()
{
float moveDir = Input.GetAxis("Horizontal");
Vector2 playerVel = new Vector2(moveDir * runSpeed, myRigidbody.velocity.y);
myRigidbody.velocity = playerVel;
}
}

第3课 如何在Unity中实现Player移动时Idle和Run动画切换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerContraller : MonoBehaviour
{
public float runSpeed;
private Rigidbody2D myRigidbody;
private Animator myAnim;
// Start is called before the first frame update
void Start()
{
// 获取组件
myRigidbody = GetComponent<Rigidbody2D>();
myAnim = GetComponent<Animator>();
}

// Update is called once per frame
void Update()
{
Flip();
Run();
}

// 左右移动,需要翻转
void Flip()
{
bool playerHasXAxisSpeed = Mathf.Abs(myRigidbody.velocity.x) > Mathf.Epsilon;
if (playerHasXAxisSpeed) // 有速度才需要翻转
{
if (myRigidbody.velocity.x > 0.1f)
{
transform.localRotation = Quaternion.Euler(0, 0, 0);
}
if (myRigidbody.velocity.x < -0.1f)
{
transform.localRotation = Quaternion.Euler(0, 180, 0);
}
}
}

void Run()
{
float moveDir = Input.GetAxis("Horizontal");
Vector2 playerVel = new Vector2(moveDir * runSpeed, myRigidbody.velocity.y);
myRigidbody.velocity = playerVel;

bool playerHasXAxisSpeed = Mathf.Abs(myRigidbody.velocity.x) > Mathf.Epsilon; // Mathf.Epsilon,接近于0,但是不等于0
myAnim.SetBool("Run", playerHasXAxisSpeed);
}
}

第4课 如何在Unity中实现Player跳跃Jump功能

Project settings -> Input Manager:查看输入

只有在地面才能跳

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerContraller : MonoBehaviour
{
public float runSpeed;
public float jumpSpeed;


private Rigidbody2D myRigidbody;
private Animator myAnim;
private BoxCollider2D myFeet;
private bool isGround;
// Start is called before the first frame update
void Start()
{
// 获取组件
myRigidbody = GetComponent<Rigidbody2D>();
myAnim = GetComponent<Animator>();
myFeet = GetComponent<BoxCollider2D>();
}

// Update is called once per frame
void Update()
{
Flip();
Run();
Jump();
CheckGround();
}

// 左右移动,需要翻转
void Flip()
{
bool playerHasXAxisSpeed = Mathf.Abs(myRigidbody.velocity.x) > Mathf.Epsilon;
if (playerHasXAxisSpeed) // 有速度才需要翻转
{
if (myRigidbody.velocity.x > 0.1f)
{
transform.localRotation = Quaternion.Euler(0, 0, 0);
}
if (myRigidbody.velocity.x < -0.1f)
{
transform.localRotation = Quaternion.Euler(0, 180, 0);
}
}
}

void CheckGround()
{
isGround = myFeet.IsTouchingLayers(LayerMask.GetMask("Ground"));
Debug.Log(isGround);
}

void Run()
{
float moveDir = Input.GetAxis("Horizontal");
Vector2 playerVel = new Vector2(moveDir * runSpeed, myRigidbody.velocity.y);
myRigidbody.velocity = playerVel;

bool playerHasXAxisSpeed = Mathf.Abs(myRigidbody.velocity.x) > Mathf.Epsilon; // Mathf.Epsilon,接近于0,但是不等于0
myAnim.SetBool("Run", playerHasXAxisSpeed);
}


void Jump()
{
if (isGround && Input.GetButtonDown("Jump"))
{
Vector2 jumpVel = new Vector2(0.0f, jumpSpeed);
myRigidbody.velocity = Vector2.up * jumpVel;
}
}
}

第5课 如何在Unity中实现Player移动跳跃时Jump, Fall, Idle, Run动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerContraller : MonoBehaviour
{
public float runSpeed;
public float jumpSpeed;


private Rigidbody2D myRigidbody;
private Animator myAnim;
private BoxCollider2D myFeet;
private bool isGround;
// Start is called before the first frame update
void Start()
{
// 获取组件
myRigidbody = GetComponent<Rigidbody2D>();
myAnim = GetComponent<Animator>();
myFeet = GetComponent<BoxCollider2D>();
}

// Update is called once per frame
void Update()
{
Flip();
Run();
Jump();
CheckGround();
SwitchAnimation();
}

// 左右移动,需要翻转
void Flip()
{
bool playerHasXAxisSpeed = Mathf.Abs(myRigidbody.velocity.x) > Mathf.Epsilon;
if (playerHasXAxisSpeed) // 有速度才需要翻转
{
if (myRigidbody.velocity.x > 0.1f)
{
transform.localRotation = Quaternion.Euler(0, 0, 0);
}
if (myRigidbody.velocity.x < -0.1f)
{
transform.localRotation = Quaternion.Euler(0, 180, 0);
}
}
}

void CheckGround()
{
isGround = myFeet.IsTouchingLayers(LayerMask.GetMask("Ground"));
Debug.Log(isGround);
}

void Run()
{
float moveDir = Input.GetAxis("Horizontal");
Vector2 playerVel = new Vector2(moveDir * runSpeed, myRigidbody.velocity.y);
myRigidbody.velocity = playerVel;

bool playerHasXAxisSpeed = Mathf.Abs(myRigidbody.velocity.x) > Mathf.Epsilon; // Mathf.Epsilon,接近于0,但是不等于0
myAnim.SetBool("Run", playerHasXAxisSpeed);
}


void Jump()
{
if (isGround && Input.GetButton("Jump"))
{
myAnim.SetBool("Jump", true);
Vector2 jumpVel = new Vector2(0.0f, jumpSpeed);
myRigidbody.velocity = Vector2.up * jumpVel;
}
}

void SwitchAnimation()
{
myAnim.SetBool("Idle", false);
if (myAnim.GetBool("Jump")) // 处在跳跃状态
{
if (myRigidbody.velocity.y < 0.0f) // 速度为0 = 达到最高点了
{
myAnim.SetBool("Jump", false);
myAnim.SetBool("Fall", true);
}
}
else if (isGround) // 到地面了
{
myAnim.SetBool("Fall", false);
myAnim.SetBool("Idle", true);
}
}
}

第6课 如何在Unity中实现Player二段跳跃Double Jump

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerContraller : MonoBehaviour
{
public float runSpeed;
public float jumpSpeed;
public float doubleJupmSpeed;


private Rigidbody2D myRigidbody;
private Animator myAnim;
private BoxCollider2D myFeet;
private bool isGround;
private bool canDoubleJump;
// Start is called before the first frame update
void Start()
{
// 获取组件
myRigidbody = GetComponent<Rigidbody2D>();
myAnim = GetComponent<Animator>();
myFeet = GetComponent<BoxCollider2D>();
}

// Update is called once per frame
void Update()
{
Flip();
Run();
Jump();
CheckGround();
SwitchAnimation();
}

// 左右移动,需要翻转
void Flip()
{
bool playerHasXAxisSpeed = Mathf.Abs(myRigidbody.velocity.x) > Mathf.Epsilon;
if (playerHasXAxisSpeed) // 有速度才需要翻转
{
if (myRigidbody.velocity.x > 0.1f)
{
transform.localRotation = Quaternion.Euler(0, 0, 0);
}
if (myRigidbody.velocity.x < -0.1f)
{
transform.localRotation = Quaternion.Euler(0, 180, 0);
}
}
}

void CheckGround()
{
isGround = myFeet.IsTouchingLayers(LayerMask.GetMask("Ground"));
Debug.Log(isGround);
}

void Run()
{
float moveDir = Input.GetAxis("Horizontal");
Vector2 playerVel = new Vector2(moveDir * runSpeed, myRigidbody.velocity.y);
myRigidbody.velocity = playerVel;

bool playerHasXAxisSpeed = Mathf.Abs(myRigidbody.velocity.x) > Mathf.Epsilon; // Mathf.Epsilon,接近于0,但是不等于0
myAnim.SetBool("Run", playerHasXAxisSpeed);
}


void Jump()
{
if (Input.GetButtonDown("Jump"))
{
if (isGround)
{
myAnim.SetBool("Jump", true);
Vector2 jumpVel = new Vector2(0.0f, jumpSpeed);
myRigidbody.velocity = Vector2.up * jumpVel;
canDoubleJump = true;
}
else if (canDoubleJump)
{
myAnim.SetBool("DoubleJump", true);
canDoubleJump = false;
Vector2 jumpVel = new Vector2(0.0f, doubleJupmSpeed);
myRigidbody.velocity = Vector2.up * jumpVel;
}
}
}

void SwitchAnimation()
{
myAnim.SetBool("Idle", false);
if (myAnim.GetBool("Jump")) // 处在跳跃状态
{
if (myRigidbody.velocity.y < 0.0f) // 速度为0 = 达到最高点了
{
myAnim.SetBool("Jump", false);
myAnim.SetBool("Fall", true);
}
}
else if (isGround) // 到地面了
{
myAnim.SetBool("Fall", false);
myAnim.SetBool("Idle", true);
}
if (myAnim.GetBool("DoubleJump")) // 处在跳跃状态
{
if (myRigidbody.velocity.y < 0.0f) // 速度为0 = 达到最高点了
{
myAnim.SetBool("DoubleJump", false);
myAnim.SetBool("DoubleFall", true);
}
}
else if (isGround) // 到地面了
{
myAnim.SetBool("DoubleFall", false);
myAnim.SetBool("Idle", true);
}
}
}

第7课 如何在Unity中实现人物攻击Player Attack(动画篇)

恢复需要延迟时间,所以不需要置零了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerContraller : MonoBehaviour
{
public float runSpeed;
public float jumpSpeed;
public float doubleJupmSpeed;


private Rigidbody2D myRigidbody;
private Animator myAnim;
private BoxCollider2D myFeet;
private bool isGround;
private bool canDoubleJump;
// Start is called before the first frame update
void Start()
{
// 获取组件
myRigidbody = GetComponent<Rigidbody2D>();
myAnim = GetComponent<Animator>();
myFeet = GetComponent<BoxCollider2D>();
}

// Update is called once per frame
void Update()
{
Flip();
Run();
Jump();
Attack();
CheckGround();
SwitchAnimation();
}

// 左右移动,需要翻转
void Flip()
{
bool playerHasXAxisSpeed = Mathf.Abs(myRigidbody.velocity.x) > Mathf.Epsilon;
if (playerHasXAxisSpeed) // 有速度才需要翻转
{
if (myRigidbody.velocity.x > 0.1f)
{
transform.localRotation = Quaternion.Euler(0, 0, 0);
}
if (myRigidbody.velocity.x < -0.1f)
{
transform.localRotation = Quaternion.Euler(0, 180, 0);
}
}
}

void CheckGround()
{
isGround = myFeet.IsTouchingLayers(LayerMask.GetMask("Ground"));
}

void Run()
{
float moveDir = Input.GetAxis("Horizontal");
Vector2 playerVel = new Vector2(moveDir * runSpeed, myRigidbody.velocity.y);
myRigidbody.velocity = playerVel;

bool playerHasXAxisSpeed = Mathf.Abs(myRigidbody.velocity.x) > Mathf.Epsilon; // Mathf.Epsilon,接近于0,但是不等于0
myAnim.SetBool("Run", playerHasXAxisSpeed);
}


void Jump()
{
if (Input.GetButtonDown("Jump"))
{
if (isGround)
{
myAnim.SetBool("Jump", true);
Vector2 jumpVel = new Vector2(0.0f, jumpSpeed);
myRigidbody.velocity = Vector2.up * jumpVel;
canDoubleJump = true;
}
else if (canDoubleJump)
{
myAnim.SetBool("DoubleJump", true);
canDoubleJump = false;
Vector2 jumpVel = new Vector2(0.0f, doubleJupmSpeed);
myRigidbody.velocity = Vector2.up * jumpVel;
}
}
}

void Attack()
{

if (Input.GetButtonDown("Attack"))
{
myAnim.SetTrigger("Attack");
}
}

void SwitchAnimation()
{
myAnim.SetBool("Idle", false);
if (myAnim.GetBool("Jump")) // 处在跳跃状态
{
if (myRigidbody.velocity.y < 0.0f) // 速度为0 = 达到最高点了
{
myAnim.SetBool("Jump", false);
myAnim.SetBool("Fall", true);
}
}
else if (isGround) // 到地面了
{
myAnim.SetBool("Fall", false);
myAnim.SetBool("Idle", true);
}
if (myAnim.GetBool("DoubleJump")) // 处在跳跃状态
{
if (myRigidbody.velocity.y < 0.0f) // 速度为0 = 达到最高点了
{
myAnim.SetBool("DoubleJump", false);
myAnim.SetBool("DoubleFall", true);
}
}
else if (isGround) // 到地面了
{
myAnim.SetBool("DoubleFall", false);
myAnim.SetBool("Idle", true);
}
}
}

第8课 如何在Unity中实现人物攻击Player Attack(Hitbox篇)

PlayerAttack.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerAttack : MonoBehaviour
{
public int damage;
public float startTime;
public float disableTime;

private Animator anim;
private PolygonCollider2D collider2D;

// Start is called before the first frame update
void Start()
{
anim = GameObject.FindGameObjectWithTag("Player").GetComponent<Animator>();
collider2D = GetComponent<PolygonCollider2D>();
}

// Update is called once per frame
void Update()
{
Attack();
}

void Attack()
{
if (Input.GetButtonDown("Attack"))
{
anim.SetTrigger("Attack");
StartCoroutine(StartAttack());
}
}

IEnumerator StartAttack()
{
yield return new WaitForSeconds(startTime);
collider2D.enabled = true;
StartCoroutine(DisableHitBox());
}

IEnumerator DisableHitBox()
{
yield return new WaitForSeconds(disableTime);
collider2D.enabled = false;
}
}

第9课 如何在Unity中实现人物攻击Player Attack(Enemy篇)

PlayerAttack.cs

1
2
3
4
5
6
7
private void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.CompareTag("Enemy"))
{
other.GetComponent<Enemy>().TakeDamege(damage);
}
}

Enemy_Bat.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Enemy_Bat : Enemy
{
// Start is called before the first frame update
public void Start()
{

}

// Update is called once per frame
public void Update()
{
base.Update();
}

}

Enemy.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class Enemy : MonoBehaviour
{
public int health;
public int damage;

// Start is called before the first frame update
public void Start()
{

}

// Update is called once per frame
public void Update()
{
if (health <= 0)
{
Destroy(gameObject);
}
}

public void TakeDamege(int damage)
{
health -= damage;
}
}

第10课 如何在Unity中实现敌人受伤后红色闪烁功能 Enemy Re

Enemy_Bat.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Enemy_Bat : Enemy
{
// Start is called before the first frame update
public void Start()
{
base.Start();
}

// Update is called once per frame
public void Update()
{
base.Update();
}
}

Enemy.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class Enemy : MonoBehaviour
{
public int health;
public int damage;
public float flashTime;

private SpriteRenderer sr;
private Color oriColor;

// Start is called before the first frame update
public void Start()
{
sr = GetComponent<SpriteRenderer>();
oriColor = sr.color;
}

// Update is called once per frame
public void Update()
{
if (health <= 0)
{
Destroy(gameObject);
}
}

public void TakeDamege(int damage)
{
health -= damage;
FlashColor(flashTime);
}

void FlashColor(float time)
{
sr.color = Color.red;
Invoke("ResetColor", time);
}

void ResetColor()
{
sr.color = oriColor;
}
}

第11课 如何在Unity中实现简单敌人AI功能 Enemy AI

Enemy_Bat.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Enemy_Bat : Enemy
{
public float speed;
public float startWaitTime;
public Transform movePose;
public Transform leftDownPos;
public Transform rightUpPos;

private float waitTime;


// Start is called before the first frame update
public void Start()
{
base.Start();
waitTime = startWaitTime;
movePose.position = GetRandomPos();
}

// Update is called once per frame
public void Update()
{
base.Update();

transform.position = Vector2.MoveTowards(transform.position, movePose.position, speed * Time.deltaTime);

if (Vector2.Distance(transform.position, movePose.position) < 0.1f)
{
if (waitTime <= 0)
{
movePose.position = GetRandomPos();
waitTime = startWaitTime;
}
else
{
waitTime -= Time.deltaTime;
}
}
}

Vector2 GetRandomPos()
{
Vector2 rndPos = new Vector2(Random.Range(leftDownPos.position.x, rightUpPos.position.x), Random.Range(leftDownPos.position.y, rightUpPos.position.y));
return rndPos;
}

}

第12课 如何在Unity中实现敌人掉血的粒子特效 Enemy Blood Effe

BloodEffect.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BloodEffect : MonoBehaviour
{
public float timeToDestory;

// Start is called before the first frame update
void Start()
{
Destroy(gameObject, timeToDestory);
}

// Update is called once per frame
void Update()
{

}
}

Enemy.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class Enemy : MonoBehaviour
{
public int health;
public int damage;
public float flashTime;
public GameObject bloodEffect;

private SpriteRenderer sr;
private Color oriColor;

// Start is called before the first frame update
public void Start()
{
sr = GetComponent<SpriteRenderer>();
oriColor = sr.color;
}

// Update is called once per frame
public void Update()
{
if (health <= 0)
{
Destroy(gameObject);
}
}

public void TakeDamege(int damage)
{
health -= damage;
FlashColor(flashTime);
Instantiate(bloodEffect, transform.position, Quaternion.identity);
}

void FlashColor(float time)
{
sr.color = Color.red;
Invoke("ResetColor", time);
}

void ResetColor()
{
sr.color = oriColor;
}
}

第13课 如何在Unity中实现相机跟随Player功能 Camera Follow

CameraFollow.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraFollow : MonoBehaviour
{
public Transform target;
public float smoothing;

// Start is called before the first frame update
void Start()
{

}

void LateUpdate()
{
if (target != null) // 玩家还没死
{
if (transform.position != target.position)
{
Vector3 targetPos = target.position;
transform.position = Vector3.Lerp(transform.position, targetPos, smoothing);
}
}
}

// Update is called once per frame
void Update()
{

}
}

第14课 如何在Unity中实现相机震动抖动 Camera Shake

CameraShake.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraShake : MonoBehaviour
{
public Animator camAnim;

// Start is called before the first frame update
void Start()
{

}

// Update is called once per frame
void Update()
{

}

public void Shake()
{
camAnim.SetTrigger("Shake");
}
}

GameController.cs

1
2
3
4
5
6
7
8
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameController : MonoBehaviour
{
public static CameraShake camShake;
}

Enemy.cs

1
2
3
4
5
6
7
public void TakeDamege(int damage)
{
health -= damage;
FlashColor(flashTime);
Instantiate(bloodEffect, transform.position, Quaternion.identity);
GameController.camShake.Shake();
}

CameraFollow.cs

1
2
3
4
void Start()
{
GameController.camShake = GameObject.FindGameObjectWithTag("CameraShake").GetComponent<CameraShake>();
}

第15课 如何在Unity中限制相机的移动范围 Camera Limit

CameraFollow.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraFollow : MonoBehaviour
{
public Transform target;
public float smoothing;

public Vector2 minPosition;
public Vector2 maxPosition;

// Start is called before the first frame update
void Start()
{
GameController.camShake = GameObject.FindGameObjectWithTag("CameraShake").GetComponent<CameraShake>();
}

void LateUpdate()
{
if (target != null) // 玩家还没死
{
if (transform.position != target.position)
{
Vector3 targetPos = target.position;
targetPos.x = Mathf.Clamp(targetPos.x, minPosition.x, maxPosition.x);
targetPos.y = Mathf.Clamp(targetPos.y, minPosition.y, maxPosition.y);
transform.position = Vector3.Lerp(transform.position, targetPos, smoothing);
}
}
}

// Update is called once per frame
void Update()
{

}

public void SetCamPosLimit(Vector2 minPos, Vector2 maxPos)
{
minPosition = minPos;
maxPosition = maxPos;
}
}

第16课 如何在Unity中实现Player受伤闪烁功能

PlayerHealth.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerHealth : MonoBehaviour
{
public int health;
public int blinks;
public float time;

private Renderer myRender;
// Start is called before the first frame update
void Start()
{
myRender = GetComponent<Renderer>();
}

// Update is called once per frame
void Update()
{

}

public void DamagePlayer(int damage)
{
health -= damage;
if (health <= 0)
{
Destroy(gameObject);
}
BlinkPlayer(blinks, time);
}

void BlinkPlayer(int numBlinks, float seconds)
{
StartCoroutine(DoBlink(numBlinks, seconds));
}

IEnumerator DoBlink(int numBlinks, float seconds)
{
for (int i = 0; i < numBlinks * 2; i++)
{
myRender.enabled = !myRender.enabled;
yield return new WaitForSeconds(seconds);
}
myRender.enabled = true;
}
}

Enemy.cs

1
2
3
4
5
6
7
8
9
10
private void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.CompareTag("Player") && other.GetType().ToString() == "UnityEngine.CapsuleCollider2D")
{
if (playerHealth != null)
{
playerHealth.DamagePlayer(damage);
}
}
}

第17课 如何在Unity中实现Player死亡功能 Player Death

解决吸墙,摩擦力导致的

新建2D材质,摩擦力置零,挂载到Player胶囊碰撞体上

死亡动画效果

PlayerHealth.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerHealth : MonoBehaviour
{
public int health;
public int blinks;
public float time;
public float dieTime;

private Renderer myRender;
private Animator anim;
// Start is called before the first frame update
void Start()
{
myRender = GetComponent<Renderer>();
anim = GetComponent<Animator>();
}

// Update is called once per frame
void Update()
{

}

public void DamagePlayer(int damage)
{
health -= damage;
if (health <= 0)
{
anim.SetTrigger("Die");
Invoke("KillPlayer", dieTime);
}
BlinkPlayer(blinks, time);
}

void KillPlayer()
{
Destroy(gameObject);
}

void BlinkPlayer(int numBlinks, float seconds)
{
StartCoroutine(DoBlink(numBlinks, seconds));
}

IEnumerator DoBlink(int numBlinks, float seconds)
{
for (int i = 0; i < numBlinks * 2; i++)
{
myRender.enabled = !myRender.enabled;
yield return new WaitForSeconds(seconds);
}
myRender.enabled = true;
}
}

第18课 如何正确理解Unity中的Layer和Sorting Layer

Layer:处理所有碰撞相关的内容

Sorting Layer:处理显示顺序的内容

有bug就看看layer碰撞设置

第19课 如何在Unity中使用2D TileMap功能

直接加Tilemap Collider 2D效率不高,可以加一个组件Composite Collider 2D,然后钢体Body Type属性改为static静态,最后勾上Tilemap Collider 2D中的Used By Composite

第20课 如何在Unity中实现Player生命值血条功能 Player Health B

HealthBar.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class HealthBar : MonoBehaviour
{
public Text healthText;
public static int HealthCurrent;
public static int HealthMax;

private Image healthBar;
// Start is called before the first frame update
void Start()
{
healthBar = GetComponent<Image>();
}

// Update is called once per frame
void Update()
{
healthBar.fillAmount = (float)HealthCurrent / (float)HealthMax;
healthText.text = HealthCurrent.ToString() + "/" + HealthMax.ToString();
}
}

PlayerHealth.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerHealth : MonoBehaviour
{
public int health;
public int blinks;
public float time;
public float dieTime;

private Renderer myRender;
private Animator anim;
// Start is called before the first frame update
void Start()
{
HealthBar.HealthMax = health;
HealthBar.HealthCurrent = health;
myRender = GetComponent<Renderer>();
anim = GetComponent<Animator>();
}

// Update is called once per frame
void Update()
{

}

public void DamagePlayer(int damage)
{
health -= damage;
if (health < 0) health = 0;
HealthBar.HealthCurrent = health;
if (health <= 0)
{
anim.SetTrigger("Die");
Invoke("KillPlayer", dieTime);
}
BlinkPlayer(blinks, time);
}

void KillPlayer()
{
Destroy(gameObject);
}

void BlinkPlayer(int numBlinks, float seconds)
{
StartCoroutine(DoBlink(numBlinks, seconds));
}

IEnumerator DoBlink(int numBlinks, float seconds)
{
for (int i = 0; i < numBlinks * 2; i++)
{
myRender.enabled = !myRender.enabled;
yield return new WaitForSeconds(seconds);
}
myRender.enabled = true;
}
}

第21课 如何在Unity中实现Player受伤时屏幕红闪功能 Screen Flas

修改了粒子效果不显示的bug

ScreenFlash.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class ScreenFlash : MonoBehaviour
{
public Image img;
public float time;
public Color flashColor;

private Color defaultColor;

// Start is called before the first frame update
void Start()
{
defaultColor = img.color;
}

// Update is called once per frame
void Update()
{

}

public void FlashScreen()
{
StartCoroutine(Flash());
}


IEnumerator Flash()
{
img.color = flashColor;
yield return new WaitForSeconds(time);
img.color = defaultColor;
}
}

修改角色死亡还能动的bug

GameController.cs

1
2
3
4
5
6
7
8
9
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameController : MonoBehaviour
{
public static bool isGameAlive;
public static CameraShake camShake;
}

PlayerHealth.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerHealth : MonoBehaviour
{
public int health;
public int blinks;
public float time;
public float dieTime;

private Renderer myRender;
private Animator anim;
private ScreenFlash sf;
private Rigidbody2D rb2d;
// Start is called before the first frame update
void Start()
{
HealthBar.HealthMax = health;
HealthBar.HealthCurrent = health;
myRender = GetComponent<Renderer>();
anim = GetComponent<Animator>();
sf = GetComponent<ScreenFlash>();
rb2d = GetComponent<Rigidbody2D>();
}

// Update is called once per frame
void Update()
{

}

public void DamagePlayer(int damage)
{
sf.FlashScreen();
health -= damage;
if (health < 0) health = 0;
HealthBar.HealthCurrent = health;
if (health <= 0)
{
rb2d.velocity = new Vector2(0, 0); // 速度置零
GameController.isGameAlive = false;
anim.SetTrigger("Die");
Invoke("KillPlayer", dieTime);
}
BlinkPlayer(blinks, time);
}

void KillPlayer()
{
Destroy(gameObject);
}

void BlinkPlayer(int numBlinks, float seconds)
{
StartCoroutine(DoBlink(numBlinks, seconds));
}

IEnumerator DoBlink(int numBlinks, float seconds)
{
for (int i = 0; i < numBlinks * 2; i++)
{
myRender.enabled = !myRender.enabled;
yield return new WaitForSeconds(seconds);
}
myRender.enabled = true;
}
}

PlayerContraller.cs

1
2
3
4
5
6
7
8
9
10
11
void Update()
{
if (GameController.isGameAlive)
{
Flip();
Run();
Jump();
CheckGround();
SwitchAnimation();
}
}

第22课 如何在Unity中实现游戏地刺陷阱功能 2D Platform Spikes

Spikes.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Spikes : MonoBehaviour
{
public int damage;

private PlayerHealth playerHealth;

// Start is called before the first frame update
void Start()
{
playerHealth = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerHealth>();
}

// Update is called once per frame
void Update()
{

}

void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Player") && other.GetType().ToString() == "UnityEngine.PolygonCollider2D")
{
playerHealth.DamagePlayer(damage);
}
}
}

PlayerHealth.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerHealth : MonoBehaviour
{
public int health;
public int blinks;
public float time;
public float dieTime;
public float hitBoxCdTime;

private Renderer myRender;
private Animator anim;
private ScreenFlash sf;
private Rigidbody2D rb2d;
private PolygonCollider2D polygonCollider2D;
// Start is called before the first frame update
void Start()
{
HealthBar.HealthMax = health;
HealthBar.HealthCurrent = health;
myRender = GetComponent<Renderer>();
anim = GetComponent<Animator>();
sf = GetComponent<ScreenFlash>();
rb2d = GetComponent<Rigidbody2D>();
polygonCollider2D = GetComponent<PolygonCollider2D>();
}

// Update is called once per frame
void Update()
{

}

public void DamagePlayer(int damage)
{
sf.FlashScreen();
health -= damage;
if (health < 0) health = 0;
HealthBar.HealthCurrent = health;
if (health <= 0)
{
rb2d.velocity = new Vector2(0, 0); // 速度置零
GameController.isGameAlive = false;
anim.SetTrigger("Die");
Invoke("KillPlayer", dieTime);
}
BlinkPlayer(blinks, time);
polygonCollider2D.enabled = false;
StartCoroutine(ShowPlayerHitBox());
}

IEnumerator ShowPlayerHitBox()
{
yield return new WaitForSeconds(hitBoxCdTime);
polygonCollider2D.enabled = true;
}

void KillPlayer()
{
Destroy(gameObject);
}

void BlinkPlayer(int numBlinks, float seconds)
{
StartCoroutine(DoBlink(numBlinks, seconds));
}

IEnumerator DoBlink(int numBlinks, float seconds)
{
for (int i = 0; i < numBlinks * 2; i++)
{
myRender.enabled = !myRender.enabled;
yield return new WaitForSeconds(seconds);
}
myRender.enabled = true;
}
}

第23课 如何在Unity中实现2D漂浮移动平台功能 Moving Platform

首先如果Player在MovingPlatform下的话,是可以一起移动的,所以将这么修改

MovingPlatform.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MovingPlatform : MonoBehaviour
{
public float speed;
public float waitTime;
public Transform[] movePos;

private int i;
private float oriWaitTime;
private Transform playerDefTransform;

// Start is called before the first frame update
void Start()
{
i = 1;
oriWaitTime = waitTime;
playerDefTransform = GameObject.FindGameObjectWithTag("Player").transform.parent;
}

// Update is called once per frame
void Update()
{
transform.position = Vector2.MoveTowards(transform.position, movePos[i].position, speed * Time.deltaTime);
if (Vector2.Distance(transform.position, movePos[i].position) < 0.1f)
{
if (waitTime < 0.0f)
{
if (i == 0) i = 1;
else i = 0;
waitTime = oriWaitTime;
}
else
{
waitTime -= Time.deltaTime;
}
}
}

void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Player") && other.GetType().ToString() == "UnityEngine.BoxCollider2D")
{
other.gameObject.transform.parent = gameObject.transform;
}
}

void OnTriggerExit2D(Collider2D other)
{
if (other.CompareTag("Player") && other.GetType().ToString() == "UnityEngine.BoxCollider2D")
{
other.gameObject.transform.parent = playerDefTransform;
}
}
}

第24课 如何在Unity中实现单向跳跃平台功能 OneWayPlatform

画Tilemap的时候按住Shift是删除

实现下面可以穿过,上面不行穿过:添加组件Platform Effector 2D,Composite Collider 2D组件勾选Used By Effector

实现按下键通过,可以暂时取消碰撞

PlayerContraller.cs

自己修改了在空中也可以跳一次,以及从地面下落的动画切换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerContraller : MonoBehaviour
{
public float runSpeed;
public float jumpSpeed;
public float doubleJupmSpeed;
public float restoreTime;


private Rigidbody2D myRigidbody;
private Animator myAnim;
private BoxCollider2D myFeet;
private bool isGround;
private bool canDoubleJump;
private bool isOnOneWayPlatform;
// Start is called before the first frame update
void Start()
{
// 获取组件
myRigidbody = GetComponent<Rigidbody2D>();
myAnim = GetComponent<Animator>();
myFeet = GetComponent<BoxCollider2D>();
}

// Update is called once per frame
void Update()
{
if (GameController.isGameAlive)
{
Flip();
Run();
Jump();
CheckGround();
SwitchAnimation();
OneWayPlatformCheck();
}
}

// 左右移动,需要翻转
void Flip()
{
bool playerHasXAxisSpeed = Mathf.Abs(myRigidbody.velocity.x) > Mathf.Epsilon;
if (playerHasXAxisSpeed) // 有速度才需要翻转
{
if (myRigidbody.velocity.x > 0.1f)
{
transform.localRotation = Quaternion.Euler(0, 0, 0);
}
if (myRigidbody.velocity.x < -0.1f)
{
transform.localRotation = Quaternion.Euler(0, 180, 0);
}
}
}

void CheckGround()
{
isGround = myFeet.IsTouchingLayers(LayerMask.GetMask("Ground"))
|| myFeet.IsTouchingLayers(LayerMask.GetMask("MovingPlatform"))
|| myFeet.IsTouchingLayers(LayerMask.GetMask("OneWayPlatform"));
isOnOneWayPlatform = myFeet.IsTouchingLayers(LayerMask.GetMask("OneWayPlatform"));
}

void Run()
{
float moveDir = Input.GetAxis("Horizontal");
Vector2 playerVel = new Vector2(moveDir * runSpeed, myRigidbody.velocity.y);
myRigidbody.velocity = playerVel;

bool playerHasXAxisSpeed = Mathf.Abs(myRigidbody.velocity.x) > Mathf.Epsilon; // Mathf.Epsilon,接近于0,但是不等于0
myAnim.SetBool("Run", playerHasXAxisSpeed);
}


void Jump()
{
if (isGround) canDoubleJump = true; // 接触过地面就获得了跳一次的机会
if (Input.GetButtonDown("Jump"))
{
if (isGround)
{
myAnim.SetBool("Jump", true);
Vector2 jumpVel = new Vector2(0.0f, jumpSpeed);
myRigidbody.velocity = Vector2.up * jumpVel;
}
else if (canDoubleJump)
{
myAnim.SetBool("DoubleJump", true);
canDoubleJump = false;
Vector2 jumpVel = new Vector2(0.0f, doubleJupmSpeed);
myRigidbody.velocity = Vector2.up * jumpVel;
}
}
}

void SwitchAnimation()
{
myAnim.SetBool("Idle", false);
if (myAnim.GetBool("Jump")) // 处在跳跃状态
{
if (myRigidbody.velocity.y < 0.0f) // 速度为0 = 达到最高点了
{
myAnim.SetBool("Jump", false);
myAnim.SetBool("Fall", true);
}
}
else if (isGround) // 到地面了
{
myAnim.SetBool("Fall", false);
myAnim.SetBool("Idle", true);
}
if (myAnim.GetBool("DoubleJump")) // 处在跳跃状态
{
if (myRigidbody.velocity.y < 0.0f) // 速度为0 = 达到最高点了
{
myAnim.SetBool("DoubleJump", false);
myAnim.SetBool("DoubleFall", true);
}
}
else if (isGround) // 到地面了
{
myAnim.SetBool("DoubleFall", false);
myAnim.SetBool("Idle", true);
}
if (!isGround && !myAnim.GetBool("Idle")
&& !myAnim.GetBool("DoubleFall")
&& !myAnim.GetBool("DoubleJump")
&& !myAnim.GetBool("Jump")
&& !myAnim.GetBool("Attack")
&& !myAnim.GetBool("Run")) // 处于站立状态,但是没有接触地面了
{
myAnim.SetBool("Idle", false);
myAnim.SetBool("Fall", true);
}
}

void OneWayPlatformCheck()
{
if (isGround && gameObject.layer != LayerMask.NameToLayer("Player"))
{
gameObject.layer = LayerMask.NameToLayer("Player");
}
float moveY = Input.GetAxis("Vertical");
if (isOnOneWayPlatform && moveY < -0.1f)
{
gameObject.layer = LayerMask.NameToLayer("OneWayPlatform");
Invoke("RestorePlayerLayer", restoreTime);
}
}

void RestorePlayerLayer()
{
if (!isGround && gameObject.layer != LayerMask.NameToLayer("Player"))
{
gameObject.layer = LayerMask.NameToLayer("Player");
}
}
}

第25课 如何在Unity中实现Player爬梯子功能 2D Ladder

自己修改了代码

梯子顶部可以和单项木板一起用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerContraller : MonoBehaviour
{
public float runSpeed;
public float jumpSpeed;
public float doubleJupmSpeed;
public float climbSpeed;
public float restoreTime;


private Rigidbody2D myRigidbody;
private Animator myAnim;
private BoxCollider2D myFeet;
private bool isGround;
private bool canDoubleJump;
private bool isOnOneWayPlatform;

private bool isLadder;
private bool isClimbing;
//private bool isJumping;
//private bool isFalling;
//private bool isDoubleJumping;
//private bool isDoubleFalling;

private float playerGravity;
// Start is called before the first frame update
void Start()
{
// 获取组件
myRigidbody = GetComponent<Rigidbody2D>();
myAnim = GetComponent<Animator>();
myFeet = GetComponent<BoxCollider2D>();
playerGravity = myRigidbody.gravityScale;
}

// Update is called once per frame
void Update()
{
if (GameController.isGameAlive)
{
//CheckAirStatus();
Flip();
Run();
Jump();
Climb();
CheckGround();
CheckLadder();
SwitchAnimation();
OneWayPlatformCheck();
}
}

// 左右移动,需要翻转
void Flip()
{
bool playerHasXAxisSpeed = Mathf.Abs(myRigidbody.velocity.x) > Mathf.Epsilon;
if (playerHasXAxisSpeed) // 有速度才需要翻转
{
if (myRigidbody.velocity.x > 0.1f)
{
transform.localRotation = Quaternion.Euler(0, 0, 0);
}
if (myRigidbody.velocity.x < -0.1f)
{
transform.localRotation = Quaternion.Euler(0, 180, 0);
}
}
}

void CheckGround()
{
isGround = myFeet.IsTouchingLayers(LayerMask.GetMask("Ground"))
|| myFeet.IsTouchingLayers(LayerMask.GetMask("MovingPlatform"))
|| myFeet.IsTouchingLayers(LayerMask.GetMask("OneWayPlatform"));
isOnOneWayPlatform = myFeet.IsTouchingLayers(LayerMask.GetMask("OneWayPlatform"));
}

void CheckLadder()
{
isLadder = myFeet.IsTouchingLayers(LayerMask.GetMask("Ladder"));
}

void Run()
{
float moveDir = Input.GetAxis("Horizontal");
Vector2 playerVel = new Vector2(moveDir * runSpeed, myRigidbody.velocity.y);
myRigidbody.velocity = playerVel;

bool playerHasXAxisSpeed = Mathf.Abs(myRigidbody.velocity.x) > Mathf.Epsilon; // Mathf.Epsilon,接近于0,但是不等于0
myAnim.SetBool("Run", playerHasXAxisSpeed);
}


void Jump()
{
if (isGround) canDoubleJump = true; // 接触过地面就获得了跳一次的机会
if (Input.GetButtonDown("Jump"))
{
if (isGround)
{
myAnim.SetBool("Jump", true);
Vector2 jumpVel = new Vector2(0.0f, jumpSpeed);
myRigidbody.velocity = Vector2.up * jumpVel;
}
else if (canDoubleJump)
{
myAnim.SetBool("DoubleJump", true);
canDoubleJump = false;
Vector2 jumpVel = new Vector2(0.0f, doubleJupmSpeed);
myRigidbody.velocity = Vector2.up * jumpVel;
}
}
}

void Climb()
{
if (isOnOneWayPlatform) isLadder = false; // 两个状态不同时存在。
if (isLadder)
{
float moveY = Input.GetAxis("Vertical");
if (moveY > 0.5f || moveY < -0.5f)
{
myAnim.SetBool("Climbing", true);
myRigidbody.gravityScale = 0.0f;
myRigidbody.velocity = new Vector2(myRigidbody.velocity.x, moveY * climbSpeed);
isClimbing = true;
}
else
{
if (isClimbing)
{
myRigidbody.velocity = new Vector2(myRigidbody.velocity.x, 0.0f);
}
//if (isJumping || isFalling || isDoubleJumping || isDoubleFalling)
//{
// //myAnim.SetBool("Climbing", false);
//}
//else
//{
// //myAnim.SetBool("Climbing", false);
// myRigidbody.velocity = new Vector2(myRigidbody.velocity.x, 0.0f);
//}
}
}
else
{
isClimbing = false;
myAnim.SetBool("Climbing", false);
myRigidbody.gravityScale = playerGravity;
}
}

void SwitchAnimation()
{
myAnim.SetBool("Idle", false);
if (myAnim.GetBool("Jump")) // 处在跳跃状态
{
if (myRigidbody.velocity.y < 0.0f) // 速度为0 = 达到最高点了
{
myAnim.SetBool("Jump", false);
myAnim.SetBool("Fall", true);
}
}
else if (isGround) // 到地面了
{
myAnim.SetBool("Fall", false);
myAnim.SetBool("Idle", true);
}
if (myAnim.GetBool("DoubleJump")) // 处在跳跃状态
{
if (myRigidbody.velocity.y < 0.0f) // 速度为0 = 达到最高点了
{
myAnim.SetBool("DoubleJump", false);
myAnim.SetBool("DoubleFall", true);
}
}
else if (isGround) // 到地面了
{
myAnim.SetBool("DoubleFall", false);
myAnim.SetBool("Idle", true);
}
//if (!isGround && !isLadder
// && !myAnim.GetBool("Idle")
// && !myAnim.GetBool("DoubleFall")
// && !myAnim.GetBool("DoubleJump")
// && !myAnim.GetBool("Jump")
// && !myAnim.GetBool("Attack")
// && !myAnim.GetBool("Climbing")
// && !myAnim.GetBool("Run")) // 处理抽搐的bug
//{
// myAnim.SetBool("Idle", false);
// myAnim.SetBool("Fall", true);
//}
}

void OneWayPlatformCheck()
{
if (isGround && gameObject.layer != LayerMask.NameToLayer("Player"))
{
gameObject.layer = LayerMask.NameToLayer("Player");
}
float moveY = Input.GetAxis("Vertical");
if (isOnOneWayPlatform && moveY < -0.1f)
{
gameObject.layer = LayerMask.NameToLayer("OneWayPlatform");
Invoke("RestorePlayerLayer", restoreTime);
}
}

void RestorePlayerLayer()
{
if (!isGround && gameObject.layer != LayerMask.NameToLayer("Player"))
{
gameObject.layer = LayerMask.NameToLayer("Player");
}
}

//void CheckAirStatus()
//{
// isJumping = myAnim.GetBool("Jump");
// isFalling = myAnim.GetBool("Fall");
// isDoubleJumping = myAnim.GetBool("DoubleJump");
// isDoubleFalling = myAnim.GetBool("DoubleFall");
//}
}

第26课 如何在Unity中实现Player捡起金币和怪物金币掉落功能 G

没有sample选项:animation窗口右上角的小按钮 点一下 展开的菜单里 有个 show samples之类的选项 点一下就出来了

CoinItem.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CoinItem : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{

}

// Update is called once per frame
void Update()
{

}

void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.CompareTag("Player") &&
other.GetType().ToString() == "UnityEngine.CapsuleCollider2D")
{
CoinUI.currentCoinQuantity += 1;
Destroy(gameObject);
}
}
}

CoinUI.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class CoinUI : MonoBehaviour
{
public int startCoinQuantity;
public Text coinQuantity;

public static int currentCoinQuantity;

// Start is called before the first frame update
void Start()
{
currentCoinQuantity = startCoinQuantity;
}

// Update is called once per frame
void Update()
{
coinQuantity.text = currentCoinQuantity.ToString();
}
}

Enemy.cs

1
2
3
4
5
6
7
8
9
public GameObject dropCoin;
public void Update()
{
if (health <= 0)
{
Instantiate(dropCoin, transform.position, Quaternion.identity);
Destroy(gameObject);
}
}

第27课 如何在Unity中实现Player靠近招牌时显示文字对话框功能

Sign.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Sign : MonoBehaviour
{
public GameObject dialogBox;
public Text text;
public string textContent;
private bool isPlayerInSign;


// Start is called before the first frame update
void Start()
{
}

// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.E) && isPlayerInSign)
{
text.text = textContent;
dialogBox.SetActive(true);
}
}

void OnTriggerEnter2D(Collider2D other)
{

if (other.gameObject.CompareTag("Player") &&
other.GetType().ToString() == "UnityEngine.CapsuleCollider2D")
{
isPlayerInSign = true;
}
}

void OnTriggerExit2D(Collider2D other)
{
if (other.gameObject.CompareTag("Player") &&
other.GetType().ToString() == "UnityEngine.CapsuleCollider2D")
{
isPlayerInSign = false;
dialogBox.SetActive(false);
}
}
}

改名了Universal RP

超级bug,不会用