您的位置:首页 > 娱乐 > 八卦 > 英文seo公司_衡阳市住建局官方网站_seo专员_关键词优化排名第一

英文seo公司_衡阳市住建局官方网站_seo专员_关键词优化排名第一

2025/2/24 6:20:24 来源:https://blog.csdn.net/akjhgi/article/details/145671701  浏览:    关键词:英文seo公司_衡阳市住建局官方网站_seo专员_关键词优化排名第一
英文seo公司_衡阳市住建局官方网站_seo专员_关键词优化排名第一

一、2D渲染

1、2D相机基本设置

上面是透视,下面是正交

2、图片资源

在Unity中,常规图片导入之后,一般不在Unity中直接使用,而是转为精灵图Sprite

将图片更改为即可使用Unity内置的图片切割功能

无论精灵图片是单个的还是多个的,都可以选择中心点

3、相关组件

 

在排序图层中,越靠下的,越先渲染

也就是说,靠近摄像机的因该是最下方的图层

二、Unity输入系统

1、按键检测

关于键盘的

if (Input.GetKeyDown(KeyCode.A))
{Debug.Log("A按下了!");
}
if (Input.GetKey(KeyCode.A))
{Debug.Log("A持续按住!");
}
if (Input.GetKeyUp(KeyCode.A))
{Debug.Log("A弹起了!");
}

 

2、鼠标检测

和键盘区别不大,只是调用的API不同

注:0是左键;1是右键;2是鼠标中键

if (Input.GetMouseButtonDown(0))
{Debug.Log("鼠标左键按下");
}
if (Input.GetMouseButton(0))
{Debug.Log("鼠标左键按住");
}
if (Input.GetMouseButtonUp(0))
{Debug.Log("鼠标左键抬起");
}

 

3、InputManager

在Unity的设置中找到输入部分,即可看到默认绑定的按键

一个简单的移动代码

float inputX = Input.GetAxis("Horizontal");
float inputY = Input.GetAxis("Vertical");
float speed = 5;
transform.Translate(Time.deltaTime * speed * new Vector3(inputX, inputY, 0));

注:这里的速度乘以时间,放在前面,避免一些不必要的消耗

三、Unity2D动画概览

1、Animator组件

先在窗口上添加一个动画组件

一定是下面这个。上面这个是比较老的技术了

2、AnimatorController:动画控制器

3、AnimationClip:动画片段 

四、动画录制 

在Unity内制作动画

在录制时,必须开启录制按钮,可以选择数据,也可以修改数据,录制时会自动记录下来

也可以添加颜色

 五、动画切换

 

通过参数进行切换,小于或者大于

 2D人物的简单移动代码

public Animator animator;
public float movespeed = 0.00001f;
public SpriteRenderer spriteRenderer;
private void Start()
{spriteRenderer= gameObject.GetComponent<SpriteRenderer>();
}// Update is called once per frame
void Update()
{animator.GetComponent<Animator>();float inputX = Input.GetAxis("Horizontal");float inputY = Input.GetAxis("Vertical");//修改动画bool isMove = inputX != 0 || inputY!=0;animator.SetBool("Move", isMove);//转向if (inputX > 0) spriteRenderer.flipX = false;else if (inputX < 0) spriteRenderer.flipX = true;//位移Vector3 pos =new Vector3(inputX * Time.deltaTime * movespeed,inputY * Time.deltaTime * movespeed,0);transform.Translate(pos, Space.Self);
}

六、动画事件

在动画的某一帧触发某个函数;

原理是:在当前动画物体上的脚本里面 是否有一个事件;必须是公开的

在此处添加动画事件;

选择动画事件代码

public void Colore()
{transform.localScale=new Vector3(3, 3, 3);Debug.Log("1");
}

 

执行到这个事件时,会执行这个函数 

七、2D物理系统

每个人都需要有碰撞器,只要有一个有刚体

事件触发函数

private void OnCollisionEnter2D(Collision2D collision)
{}
private void OnCollisionStay2D(Collision2D collision)
{}
private void OnCollisionExit2D(Collision2D collision)
{}

碰撞与触发不能共存

触发函数代码

private void OnTriggerEnter2D(Collider2D collision)
{}
private void OnTriggerStay2D(Collider2D collision)
{}
private void OnTriggerExit2D(Collider2D collision)
{}

 八、主角控制(综合案例)

在玩家身上挂载一个触发器,不需要碰撞

挂载脚本

public class Game : MonoBehaviour
{public Animator animator;public float movespeed;public SpriteRenderer spriteRenderer;bool Big=false;private void Start(){spriteRenderer= gameObject.GetComponent<SpriteRenderer>();}// Update is called once per framevoid Update(){animator.GetComponent<Animator>();float inputX = Input.GetAxis("Horizontal");float inputY = Input.GetAxis("Vertical");//修改动画bool isMove = inputX != 0 || inputY!=0;animator.SetBool("Move", isMove);//转向if (inputX > 0) spriteRenderer.flipX = false;else if (inputX < 0) spriteRenderer.flipX = true;//位移Vector3 pos =new Vector3(inputX * Time.deltaTime * movespeed,inputY * Time.deltaTime * movespeed,0);transform.Translate(pos, Space.Self);}}

由于人物比较小,调节一下摄像机距离

九、发射子弹

子弹一般都是预制体;

需要一个公开获取预制体;一个生成子弹的点位;一个if循环判断按键和实例化

子弹飞行是自己的逻辑;挂载在预制体上面;

private void Shoot()
{if (Input.GetKeyDown(KeyCode.J)){//实例化GameObject star=GameObject.Instantiate(starPrefab);star.transform.position = starShootPoint.position;}
}

创建一个动画,模拟子弹射出

旋转360° 然后旋转720°

将动画勾选为循环

在预制体子弹上面挂在一个动画状态机,放入旋转动画

挂载子弹的代码

public float moveSpeed;private Vector3 moveDir;public float destroyTime=3;private float destroyTimer;//计时器public void Init(Vector3 dir){moveDir = dir;destroyTimer = destroyTime;}// Update is called once per framevoid Update(){transform.Translate(moveSpeed * Time.deltaTime * moveDir,Space.World);if (destroyTimer <= 0){Destroy(gameObject);}else{destroyTimer-=Time.deltaTime;}}

由于子弹自身有旋转,所以坐标会一直更改,需要传入一个方向初始化

在玩家代码中调用

//实例化
GameObject star=GameObject.Instantiate(starPrefab);
star.transform.position = starShootPoint.position;
bool isRightDir = spriteRenderer.flipX == false;
Vector3 moveDir = isRightDir ? transform.right : -transform.right;
Debug.Log(moveDir);
star.GetComponent<Star>().Init(moveDir);

先实例化这个预制体;把生成点赋值给预制体的当前坐标

通过bool判断是左还是右

然后获取预制体代码中的初始化方法,并传入方向

然后写一个计时器,让子弹销毁

public class Game : MonoBehaviour
{public Animator animator;public float movespeed;public SpriteRenderer spriteRenderer;public GameObject starPrefab;public Transform starShootPoint;//CDprivate float shootCD = 1;private float shootCDTimer;private void Start(){spriteRenderer= gameObject.GetComponent<SpriteRenderer>();}// Update is called once per framevoid Update(){Move(); Shoot();}private void Move(){animator.GetComponent<Animator>();float inputX = Input.GetAxis("Horizontal");float inputY = Input.GetAxis("Vertical");//修改动画bool isMove = inputX != 0 || inputY != 0;animator.SetBool("Move", isMove);//转向if (inputX > 0) spriteRenderer.flipX = false;else if (inputX < 0) spriteRenderer.flipX = true;//位移Vector3 pos =new Vector3(inputX * Time.deltaTime * movespeed,inputY * Time.deltaTime * movespeed,0);transform.Translate(pos, Space.Self);}private void Shoot(){if (shootCDTimer > 0){shootCDTimer-= Time.deltaTime;return;}if (Input.GetKeyDown(KeyCode.J)){shootCDTimer = shootCD;//实例化GameObject star=GameObject.Instantiate(starPrefab);star.transform.position = starShootPoint.position;bool isRightDir = spriteRenderer.flipX == false;Vector3 moveDir = isRightDir ? transform.right : -transform.right;Debug.Log(moveDir);star.GetComponent<Star>().Init(moveDir);}}
}

十、怪物生成

1、配置一些坐标生成怪物

创建一个空物体,挂载怪物的代码

对怪物的基础配置进行设置:

这里有一个方法;使用class类,然后把这个类作为一个数组,公开这个数组为public即可

/// <summary>
/// 怪物生成点
/// </summary>
[Serializable]
public class MonsterSpawnPoint
{public Transform spawnPoint;//生成点public GameObject monsterPrefab;//怪物预制体public float spawnInterval;//怪物生成间隔//这里的计时器不想序列化,但是需要获取,所以改为属性public float SpawnTimer { get; set; }
}
public MonsterSpawnPoint[] monsterSpawnPoints;

 

小技巧:把动画片段全部选中拖拽进入层级面板中,可以快速地生成动画和动画状态

2、按照一个频率生成怪物

现在面板上设置了预制体和生成间隔

我们做一个计时器,计时器命名为Timer

用一个for循环遍历这5个数组

声明一个局部变量类,让每一次循环都赋值给这个局部变量类,也就是每一次循环Point都获取了数组中的参数;

使用计时器,先让他小于零;

做一个判断如果小于零,那么就把生成间隔赋值给计时器;

并且实例化类中的预制体,把类中的生成点赋值给怪物的当前位置;

private void Update()
{for (int i=0;i< monsterSpawnPoints.Length;i++){MonsterSpawnPoint point= monsterSpawnPoints[i];point.SpawnTimer-=Time.deltaTime;//这里的计时器一开始就会小于零if (point.SpawnTimer <= 0)//一定会小于零{point.SpawnTimer = point.spawnInterval;//就把生成间隔赋值给计时器GameObject monster = GameObject.Instantiate(point.monsterPrefab);monster.transform.position = point.spawnPoint.position;}}
}

现在对代码进行一下优化,

public class MonsterManager : MonoBehaviour
{/// <summary>/// 怪物生成点/// </summary>[Serializable]public class MonsterSpawnPoint{public Transform spawnPoint;//生成点public GameObject monsterPrefab;//怪物预制体public float spawnInterval;//怪物生成间隔//这里的计时器不想序列化,但是需要获取,所以改为属性public float SpawnTimer { get; set; }public void Update(float deltaTime){SpawnTimer -= Time.deltaTime;//这里的计时器一开始就会小于零if (SpawnTimer <= 0)//一定会小于零{SpawnTimer = spawnInterval;//就把生成间隔赋值给计时器GameObject monster = GameObject.Instantiate(monsterPrefab);monster.transform.position = spawnPoint.position;}}}public MonsterSpawnPoint[] monsterSpawnPoints;private void Update(){for (int i=0;i< monsterSpawnPoints.Length;i++){monsterSpawnPoints[i].Update(Time.deltaTime);}}
}

因为update中调用其他类中的变量,不如直接调用update封装起来

所以在Update中定义一个参数(时间),因为调用这个update传入的参数是Time.deltatime

把生成的逻辑封装起来在Update中

在主update中,每一个for循环之后,数组的第i次循环调用这个UPdate,并传入每时每秒。

十一、怪物移动逻辑

一直去追玩家,如果解除了玩家则玩家失败;

首先把玩家设置成单例;在怪物类中先设置一个判断;判断玩家是否为空,也就是死亡状态

if (Game.Instance == null) return;

计算玩家到敌人的距离,方法是使用向量,用敌人的当前坐标 减去 自己的当前坐标

Vector3 moveDir=Game.Instance.transform.position-transform.position;

 然后进行位移

transform.Translate(moveSpeed * Time.deltaTime * moveDir,Space.World);

 此时敌人背面朝着敌人移动,所以使用Bool判断玩家在左或者右

 如果玩家的坐标小于怪物的坐标,说明是在左侧,那么更改怪物的缩放值X

bool isRight=transform.position.x>Game.Instance.transform.position.x;
if (isRight) transform.localScale = new Vector3(-1, 1, 1);
else transform.localScale = new Vector3(1, 1, 1);

 

十二、子弹消灭怪物

1、怪物被攻击,减少血量

首先,把死亡的动画片段拖进两个敌人的动画控制器中

我选择使用触发 作为死亡的条件

//接触子弹
if (collision.gameObject.CompareTag("Bullet"))
{Destroy(collision.gameObject);//取消子弹穿透hp -= 1;if (hp == 0){animator.SetTrigger("Death");}
}

如果血量为零,则播放死亡动画 

2、血量为0,播放死亡动画,销毁自己

#region 动画事件private void OnDeathAnimationEnd(){Destroy(gameObject);}
#endregion

 在死亡动画的最后一帧执行销毁

十三、鼠标指向为攻击方向 

使用屏幕坐标 到 世界坐标 

public new Camera camera;Vector3 mouseWorldPosition=camera.ScreenToWorldPoint(Input.mousePosition);

获取到的屏幕坐标,因为两个方法都需要,所以作为参数传进来 

十四、玩家生命值以及状态 

不适用UI;

把血条作为摄像机的子物体,防止血条跟随摄像机改变位置;

不让摄像机在玩家的子物体下,通过代码跟随

使用LateUpdate,让摄像机慢一帧追逐玩家

public Transform target;
private void LateUpdate()
{transform.position = target.position;
}

 此时,出现问题。

因为2d的,摄像机到玩家的距离是-10,运行后摄像机与玩家重合会看不见

修改代码,固定Z轴坐标

Vector3 pos=target.position;
pos.z = -10;
transform.position = pos;

因为血条是几张图片切换实现的

所以,在玩家身上公开一个变量HP,把Hp设置为字段,get无所谓,set设置切换 

[SerializeField]private int hp;
public int Hp 
{get => hp;set{ hp = value;} 
}

然后引用血量图,做成一个数组 

public SpriteRenderer hpSpriteRenderer;
public Sprite[] spriteRenderers;

然后在字段中,把精灵图第几个赋值给血条上 

public int Hp 
{get => hp;set{ hp = value;hpSpriteRenderer.sprite = hpSprites[hp];} 
}

初始化中,把数组长度作为血量值传进来

private void Awake()
{Instance = this;Hp = hpSprites.Length-1;
}

十五、怪物干掉玩家

怪物碰到玩家,掉血,玩家掉血为0则死亡

在此处遇到问题:怪物与玩家无法碰撞,碰撞代码逻辑未执行;

原因是刚体的数值未设置正确。

public class CameraController : MonoBehaviour
{public Transform target;private Game game1;private void Awake(){game1 = FindObjectOfType<Game>();if (game1 == null){Debug.Log("没找到");}}private void LateUpdate(){int xue = game1.Hp;Debug.Log(xue);if (xue == 0){return;}Vector3 pos=target.position;pos.z = -10;transform.position = pos;}
}

 

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;//using UnityEngine.Windows;public class Game : MonoBehaviour
{public static Game Instance;public Animator animator;public float movespeed;public SpriteRenderer spriteRenderer;public GameObject starPrefab;public Transform starShootPoint;public new Camera camera;[SerializeField]private int hp;public SpriteRenderer hpSpriteRenderer;public Sprite[] hpSprites;//CDprivate float shootCD = 0.1f;private float shootCDTimer;public int Hp {get => hp;set{ hp = value;hpSpriteRenderer.sprite = hpSprites[hp];if (hp == 0){Dead();}} }private void Awake(){Instance = this;Hp = hpSprites.Length-1;}private void Start(){spriteRenderer= gameObject.GetComponent<SpriteRenderer>();}// Update is called once per framevoid Update(){Debug.Log(Hp);Vector3 mouseWorldPosition=camera.ScreenToWorldPoint(Input.mousePosition);//Debug.Log(mouseWorldPosition);Move(mouseWorldPosition); Shoot(mouseWorldPosition);}private void Move(Vector3 mouseWorldPosition){animator.GetComponent<Animator>();float inputX = Input.GetAxis("Horizontal");float inputY = Input.GetAxis("Vertical");//修改动画bool isMove = inputX != 0 || inputY != 0;animator.SetBool("Move", isMove);//转向if (mouseWorldPosition.x > transform.position.x) spriteRenderer.flipX = false;else if (mouseWorldPosition.x < transform.position.x) spriteRenderer.flipX = true;//位移Vector3 pos =new Vector3(inputX * Time.deltaTime * movespeed,inputY * Time.deltaTime * movespeed,0);transform.Translate(pos, Space.Self);}private void Shoot(Vector3 mouseWorldPosition){if (shootCDTimer > 0){shootCDTimer-= Time.deltaTime;return;}if (Input.GetMouseButton(0)){shootCDTimer = shootCD;//实例化GameObject star=GameObject.Instantiate(starPrefab);star.transform.position = starShootPoint.position;Vector3 moveDir = (mouseWorldPosition - transform.position).normalized;star.GetComponent<Star>().Init(moveDir);}}internal void Hurt(){if (Hp <= 0) return;Hp -= 1;}private void Dead(){animator.SetTrigger("Dead");}private void DestroyPlayer(){Destroy(gameObject);}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Monster : MonoBehaviour
{public float moveSpeed;public int hp;public Animator animator;private void Update(){if (Game.Instance == null) return;Vector3 moveDir=Game.Instance.transform.position-transform.position;transform.Translate(moveSpeed * Time.deltaTime * moveDir,Space.World);bool isRight=transform.position.x>Game.Instance.transform.position.x;if (isRight) transform.localScale = new Vector3(-1, 1, 1);else transform.localScale = new Vector3(1, 1, 1);}private void OnTriggerEnter2D(Collider2D collision){Debug.Log("碰撞对象标签:" + collision.gameObject.tag);if (hp == 0) return;//接触子弹if (collision.gameObject.CompareTag("Bullet")){Debug.Log("子弹接触怪物了");Destroy(collision.gameObject);//取消子弹穿透hp -= 1;if (hp == 0){animator.SetTrigger("Death");}}else{//接触玩家if (collision.gameObject.CompareTag("Player")){Debug.Log("11");collision.gameObject.GetComponent<Game>().Hurt();Debug.Log("怪物接触玩家了");}}}#region 动画事件private void OnDeathAnimationEnd(){Destroy(gameObject);}
#endregion}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com