10月1日
npc对话
参考https://blog.csdn.net/weixin_43673589/article/details/106559650
对象层级
将Canvas
设为世界空间以绑定在npc身上
给npc添加脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class NPC : MonoBehaviour {
public GameObject dialog;
public GameObject tip;
public Text text;
public float showTime = 2;
private float showTimer;
private bool isShow = false;
private bool isEnter = false;
void Start () {
tip.SetActive (false);
dialog.SetActive (false);
showTimer = -1;
}
void Update () {
if (isEnter) {
if (Input.GetKeyDown (KeyCode.E)) {
Showdialog ();
}
}
if (isShow) {
showTimer -= Time.deltaTime;
if (showTimer < 0) {
dialog.SetActive (false);
isShow = false;
}
}
}
private void OnTriggerEnter2D (Collider2D other) {
if (other.tag == "Player") {
tip.SetActive (true);
isEnter = true;
}
}
private void OnTriggerExit2D (Collider2D other) {
if (other.tag == "Player") {
isEnter=false;
tip.SetActive (false);
}
}
public void Showdialog () {
text.text = "你好!";
isShow = true;
showTimer = showTime;
dialog.SetActive (true);
tip.SetActive (false);
}
}
npc要添加Collider2D
,并勾选触发器选项
玩家要有Collider2D
和Rigidbody2D
关于Collider2D
的碰撞https://blog.csdn.net/youxijishu/article/details/104259317
效果
爬梯子
制作一个平台以及一个梯子
给梯子添加collider
,并在顶端的位置再添加一个带有collider
的对象
增加的代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour {
public Transform ladderCheck; //梯子
public Transform ladderTopCheck;
public LayerMask ladder;
public LayerMask ladderTop;
public bool isLadder, isLadderTop;
void Update () {
if (isLadder) {
if (!isLadderTop) {
if (Input.GetKey (KeyCode.W)) {
rb.velocity = new Vector2 (rb.velocity.x, 1);
}
}
if (Input.GetKey (KeyCode.S)) {
if (isGround) {
platform.GetComponent<Collider2D> ().enabled = false;
}
rb.velocity = new Vector2 (rb.velocity.x, -1);
}
}
}
private void FixedUpdate () {
isLadderTop = Physics2D.OverlapCircle (ladderTopCheck.position, 0.1f, ladderTop); //判断是否在梯子顶端
}
private void OnTriggerEnter2D (Collider2D other) {
if (other.tag == "Ladder") {
isLadder = true;
transform.GetComponent<Rigidbody2D> ().gravityScale = 0;
if (!isLadderTop) {
platform.GetComponent<Collider2D> ().enabled = false;
}
}
}
private void OnTriggerExit2D (Collider2D other) {
if (other.tag == "Ladder") {
isLadder = false;
transform.GetComponent<Rigidbody2D> ().gravityScale = 1;
platform.GetComponent<Collider2D> ().enabled = true;
}
}
}
ladderTop
的检测方式和ground
的检测方式一样
ladder
和ladderTop
的collider
的最高点要一致
效果
角色冲刺
关键代码
使用MovePosition
函数移动到指定位置
if (Input.GetKey(KeyCode.LeftShift)) {
Vector2 velocity = new Vector2(horizontalMove, 0)*sprintDistance;
rb.MovePosition(rb.position + velocity * Time.fixedDeltaTime);
}
效果
释放火球
准备一张火球的图片,制作成prefab
玩家脚本添加
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour {
public int playerDirection; //玩家面对方向
public int playerType; //玩家元素
void Update () {
if(Input.GetMouseButtonDown(0)){
skillRelease();
}
if(Input.GetKeyDown(KeyCode.D)){
playerDirection=1; //向右
}
if(Input.GetKeyDown(KeyCode.A)){
playerDirection=-1; //向右
}
}
//技能释放
private void skillRelease () {
switch (playerType) {
case 1:
GameObject objPrefab = (GameObject) Resources.Load ("Prefabs/playerFireBall");
objPrefab.transform.GetComponent<playerFireBall>().moveDirection=playerDirection;
Instantiate (objPrefab, transform.position, transform.rotation);
break;
case 2:
break;
case 3:
break;
}
}
}
火球脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class playerFireBall : MonoBehaviour
{
// Start is called before the first frame update
public float moveSpeed;
public float maxMoveDistance; //最大移动距离
private float moveDistance; //移动距离
public int moveDirection; //移动方向
private Vector3 startPosition; //起始位置
void Start()
{
startPosition=transform.position;
}
void Update()
{
transform.Translate(Vector3.right*moveDirection *moveSpeed * Time.deltaTime);
moveDistance=Mathf.Abs((transform.position-startPosition).x);
if(moveDistance>=maxMoveDistance){
Destroy(gameObject);
}
}
}
效果
火焰与草丛互动
制作三种不同状态的草丛prefab
,设定同一个taggrass
,并添加collider
将它们都添加同一个Object.cs
脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Object : MonoBehaviour {
public bool isOnFire;
public bool isFired;
public int objType;
private float fireTimer;
public float fireTime;
private float growTimer; //生长时间
public float growTime;
void Start () {
}
void Update () {
if (isOnFire) { //正在燃烧
if (fireTimer < fireTime) {
fireTimer += Time.deltaTime;
}
else {
GameObject firedGrassPb=(GameObject) Resources.Load ("Prefabs/firedGrass");
firedGrassPb.transform.GetComponent<Object>().isFired=true;
Instantiate(firedGrassPb,transform.position,transform.rotation);
Destroy (gameObject);
}
}
if (isFired) { //烧完了
if (growTimer < growTime) {
growTimer += Time.deltaTime;
}
else {
GameObject grassPb=(GameObject) Resources.Load ("Prefabs/grass");
Instantiate(grassPb,transform.position,transform.rotation);
Destroy (gameObject);
}
}
}
}
fireGrass
预制体勾选isOnFire
,firedGrass
预制体勾选isFired
fireTime
,GrowTime
分别表示烧完,生长所需时间
修改火球的脚本
playerFireBall.cs
private void OnTriggerEnter2D (Collider2D other) {
if (other.tag == "grass") {
if (!other.transform.GetComponent<Object> ().isOnFire && !other.transform.GetComponent<Object> ().isFired) {
Destroy (gameObject);
GameObject fireGrassPb = (GameObject) Resources.Load ("Prefabs/fireGrass");
fireGrassPb.transform.GetComponent<Object> ().isOnFire = true;
Instantiate (fireGrassPb, other.transform.position, other.transform.rotation);
Destroy (other.gameObject);
}
}
}
效果
10月2日
元素交互
水与火
照葫芦画瓢,做一个放水球的功能,新建名为playerSkill.cs
的脚本,并把之前playerFireBall.cs
中的内容复制过去,然后给水球和火球都绑定playerSkill
脚本
假设潮湿的草遇到火元素会烘干,然后有蒸发的特效,燃烧的草遇到水则会被扑灭
简单制作一个蒸发的粒子特效
首先新建一个water
材质球,然后修改Shader,选择水滴的图片
然后新建steam
粒子,将water
作为材质,并适当修改粒子的属性
再制作潮湿和烘干的草丛预制体
被扑灭草丛
修改playerSkill.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class playerSkill : MonoBehaviour {
private enum skillTypes {
fire,
water,
wind
}
public int skillType; //技能类型
public float moveSpeed; //移动速度
public float maxMoveDistance; //最大移动距离
private float moveDistance; //移动距离
public int moveDirection; //移动方向
private Vector3 startPosition; //起始位置
void Start () {
startPosition = transform.position; //其实位置
}
void Update () {
//移动超过一定距离销毁
transform.Translate (Vector3.right * moveDirection * moveSpeed * Time.deltaTime);
moveDistance = Mathf.Abs ((transform.position - startPosition).x);
if (moveDistance >= maxMoveDistance) {
Destroy (gameObject);
}
}
private void OnTriggerEnter2D (Collider2D other) {
//元素与物品交互(碰撞)
if (other.tag == "grass") {
Object grass = other.transform.GetComponent<Object> ();
switch (skillType) {
//火技能
case (int) skillTypes.fire:
//草丛没有燃烧 没有烧尽 没有潮湿 没有被扑灭
if (!grass.isOnFire && !grass.isFired && !grass.isOnWater&&!grass.isOutfire) {
Destroy (gameObject);
GameObject fireGrassPb = (GameObject) Resources.Load ("Prefabs/fireGrass");
Instantiate (fireGrassPb, other.transform.position, other.transform.rotation);
Destroy (other.gameObject);
}
//潮湿的草丛
if (grass.isOnWater) {
Destroy (gameObject);
GameObject waterGrassPb = (GameObject) Resources.Load ("Prefabs/dryingGrass");
Instantiate (waterGrassPb, other.transform.position, other.transform.rotation);
Destroy (other.gameObject);
GameObject steam = (GameObject) Resources.Load ("Prefabs/steam");
Instantiate (steam);
}
break;
//水技能
case (int) skillTypes.water:
//草丛没有燃烧 没有烧尽 没有被扑灭
if (!grass.isOnFire && !grass.isFired&&!grass.isOutfire) {
Destroy (gameObject);
GameObject waterGrassPb = (GameObject) Resources.Load ("Prefabs/waterGrass");
Instantiate (waterGrassPb, other.transform.position, other.transform.rotation);
Destroy (other.gameObject);
}
//草丛正在燃烧
if (grass.isOnFire) {
}
break;
}
}
}
}
Object.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Object : MonoBehaviour {
public bool isOnFire;
public bool isFired; //烧尽
public bool isOnWater;
public bool isDrying; //烘干
public int objType;
private float fireTimer;
public float fireTime;
private float growTimer; //生长时间
public float growTime;
public float dryTime; //烘干时间
private float dryTimer;
void Start () {
}
void Update () {
if (isOnFire) { //正在燃烧
if (fireTimer < fireTime) {
fireTimer += Time.deltaTime;
}
else {
GameObject firedGrassPb=(GameObject) Resources.Load ("Prefabs/firedGrass");
Instantiate(firedGrassPb,transform.position,transform.rotation);
Destroy (gameObject);
}
}
if (isFired) { //烧完了
if (growTimer < growTime) {
growTimer += Time.deltaTime;
}
else {
GameObject grassPb=(GameObject) Resources.Load ("Prefabs/grass");
Instantiate(grassPb,transform.position,transform.rotation);
Destroy (gameObject);
}
}
if(isDrying){
if (dryTimer<dryTime) {
dryTimer += Time.deltaTime;
}
else {
GameObject grassPb=(GameObject) Resources.Load ("Prefabs/grass");
Instantiate(grassPb,transform.position,transform.rotation);
Destroy (gameObject);
}
}
}
}
效果
火与风
风有概率吹出草丛里的道具
制作风技能
制作加血道具
为了方便给Object
添加isNormal
属性,表示正常状态
prob
表示发生某事件概率
给grass
预制件勾选上
playerSkill
脚本
case (int) skillTypes.wind:
if (grass.isNormal) {
Destroy (gameObject);
//概率吹出道具
int prob = Random.Range (0, 100);
if (prob < other.transform.GetComponent<Object> ().prob) {
GameObject hearteGrassPb = (GameObject) Resources.Load ("Prefabs/heart");
Instantiate (hearteGrassPb, other.transform.position, other.transform.rotation);
}
Destroy (other.gameObject);
}
效果
风吹向燃烧的草丛会引发爆炸
制作爆炸预制件(同蒸发效果)
使主角与爆炸粒子碰撞会掉血
首先开启粒子的碰撞效果
然后在player
的OnParticleCollision
方法中写碰撞粒子后的事件
public Transform hearts; //血条
void Start () {
hearts = GameObject.Find ("hearts").transform;
bloodNum = hearts.GetComponent<hearts> ().bloodNum;
}
private void OnParticleCollision (GameObject other) {
if (other.tag == "explode") {
changeBlood (-1);
}
}
private void OnTriggerEnter2D (Collider2D other) {
if(other.tag=="heart"){
changeBlood(1);
Destroy(other.gameObject);
}
}
private void changeBlood (int type) {
//1是加血 -1是减血
if (type == 1) {
if (bloodNum < maxBloodtNum) {
bloodNum += 1;
hearts.GetComponent<hearts> ().changeBlood(type);
}
}
else if (type == -1) {
if (bloodNum > 0) {
bloodNum -= 1;
hearts.GetComponent<hearts> ().changeBlood(type);
}
}
}
heart.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class hearts : MonoBehaviour {
public Transform heart0;
public Transform heart1;
public Transform heart2;
public List<Transform> heartList;
public int maxBloodNum;
public int bloodNum;
void Start () {
heartList = new List<Transform> ();
heartList.Add (heart0);
heartList.Add (heart1);
heartList.Add (heart2);
if (bloodNum != maxBloodNum) {
for (int i = 0; i < maxBloodNum - bloodNum; i++) {
heartList[maxBloodNum-i-1].GetChild (1).GetComponent<Image> ().enabled = false;
}
}
}
void Update () {
}
public void changeBlood (int type) {
if (type == 1) {
if (bloodNum < maxBloodNum) {
heartList[bloodNum].GetChild (1).GetComponent<Image> ().enabled = true;
bloodNum += 1;
}
}
else if (type == -1) {
if (bloodNum > 0) {
bloodNum -= 1;
heartList[bloodNum].GetChild (1).GetComponent<Image> ().enabled = false;
}
}
}
}
效果
10月3日
主角攻击(击剑)
准备一张剑的图片,添加collider
,勾选触发器
添加一个剑平移(击剑)的简单动画
绑定在角色身上
player
public GameObject sword; //武器 剑
void Start () {
sword = GameObject.Find ("sword");
}
void Update () {
//普通攻击
if (Input.GetMouseButtonDown (0)) {
sword.transform.GetComponent<Animation>().Play ("swordAttack");
}
}
效果
新物品:箱子
箱子与元素的交互 部分遵循与草丛的交互规则
普通箱子不可打破,潮湿箱子可以被打破
制作不同的箱子,添加collider
和rigidbody
给Object
添加
private void OnTriggerStay2D (Collider2D other) {
if (objType == (int) objTypes.woodenBox) {
//潮湿的箱子可打破
if(isOnWater){
if (other.tag == "sword") {
if (other.transform.GetComponent<Animation> ().IsPlaying ("swordAttack")) {
Destroy (gameObject);
}
}
}
}
}
效果
相机跟随
给相机添加CameraFollow.cs
脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraFollow : MonoBehaviour {
public Transform player;
//设定一个角色能看到的最远值
public float Ahead;
//设置一个摄像机要移动到的点
public Vector3 targetPos;
//设置一个缓动速度插值
public float smooth;
void Start () {
}
void Update () {
targetPos = new Vector3 (player.position.x, gameObject.transform.position.y, gameObject.transform.position.z);
if (player.position.x > 0f) {
targetPos = new Vector3 (player.position.x + Ahead, gameObject.transform.position.y, gameObject.transform.position.z);
}
else {
targetPos = new Vector3 (player.position.x - Ahead, gameObject.transform.position.y, gameObject.transform.position.z);
}
transform.position = Vector3.Lerp (transform.position, targetPos, smooth * Time.deltaTime);
}
}
切换角色时改变相机的player
注意要传入Instantiate
后的对象而不是prefab
对象
Player.cs
if (Input.GetKeyDown (KeyCode.Alpha1)) {
GameObject objPrefab = (GameObject) Resources.Load ("Prefabs/playerCat");
GameObject player= Instantiate (objPrefab, transform.position, transform.rotation);
changePlayerCamera (player);
DestroyImmediate (gameObject);
}
private void changePlayerCamera (GameObject player) {
GameObject camera = GameObject.Find ("MainCamera");
camera.GetComponent<CameraFollow> ().player = player.transform;
}
效果
视差效果
https://www.bilibili.com/video/BV1Zx411X72x?from=search&seid=14704518843659195740
随便制作两个背景
BackgroundParallax.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BackgroundParallax : MonoBehaviour {
public new Camera camera; //摄像机对象
public Transform[] backgrounds; //不同层次的背景
public float[] parallaxScales; //每个层次的视差比例(即背景与摄影机的移动量的比例)
public float smoothTime; //看做是速度的倒数就好~
private Vector3 lastCameraPosition; //上一次相机的位置,用于计算滚动量
private Vector3 velocity; //速度向量,Vector3.SmoothDamp用到的变量
void Start () {
lastCameraPosition = camera.transform.position; //初始化lastCameraPosition
velocity = Vector3.zero; //初始化velocity
}
void Update () {
//遍历每个层次的背景
for (int i = 0, count = backgrounds.Length; i < count; i++) {
Vector3 parallax = (lastCameraPosition - camera.transform.position) * parallaxScales[i]; //计算滚动量(滚动距离=摄像机移动距离*视差比例)
parallax.z = 0f; //设置z轴滚动量为0,防止背景前后移动
Vector3 target = backgrounds[i].position + parallax; //目标坐标=当前背景坐标+滚动量
backgrounds[i].position = Vector3.SmoothDamp (backgrounds[i].position, target, ref velocity, smoothTime); //用Vector3.SmoothDamp将背景平滑移动
}
lastCameraPosition = camera.transform.position; //更新lastCameraPosition
}
}
将该脚本绑定到摄像机上,调整参数
效果