unity学习笔记(三)

news/2024/11/15 17:34:01/文章来源:https://www.cnblogs.com/StadarkBlog/p/18391975

综合练习小案例

玩家控制

基本流程

  • 设定移速(全局,以便在unity界面中直接修改)(如public float speed = 5;

  • 将移动单独封装成方法

  • 在移动方法中完成获取输入设置移动动画设置移动时朝向以及移动角色

     private void Move(){//获取输入int inputX = (int)UnityEngine.Input.GetAxisRaw("Horizontal");int inputY = (int)UnityEngine.Input.GetAxisRaw("Vertical");//设置动画bool isMoving = (inputX!= 0 || inputY!= 0);animator.SetBool("Move", isMoving);//设置角色的朝向if (inputX > 0) transform.localScale = new Vector3(5, 5, 1);else if (inputX < 0) transform.localScale = new Vector3(-5, 5, 1);//移动角色Vector3 moveDirection = new Vector3(inputX, inputY, 0);transform.Translate(moveDirection * moveSpace * Time.deltaTime);}
    

要点:

  • 最好给玩家同时添加碰撞体(人形的话椭圆形最好)和刚体,并设置为触发器,以在节约资源的情况下完成与其他物体的互动(物理碰撞,被攻击死亡之类的)
  • 当获取X,Y轴输入时,GetAxis()函数传递的值类型为float,移动效果为有惯性
    GetAxisRaw()函数传递的值类型为int,移动效果为无惯性。注意区分并转换类型

发射子弹

基本流程

  • 在角色上创建一个空物体作为子弹发生点

  • 需要给操作角色封装一个攻击方法的同时,给子弹一个运行脚本

  • 攻击方法:
    实例化子弹(gemPrefab需要在unity中选中) -> 子弹发射(移动)

    public GameObject gemPrefab;
    public Transform gemShootPoint;
    public float shootCD = 1;
    private float shootCDTimer;private void Attack(){//子弹冷却if (shootCDTimer > 0){shootCDTimer -= Time.deltaTime;//如果子弹冷却时间未到,则不发射子弹return;}//按下空格发射子弹if (UnityEngine.Input.GetKeyDown(KeyCode.Space)){//设置子弹冷却时间shootCDTimer = shootCD;//实例化一个Gem子弹GameObject gem = GameObject.Instantiate(gemPrefab);//设置子弹的位置gem.transform.position = gemShootPoint.position;//设置子弹的方向bool isRight = transform.localScale.x == 5;Vector3 moveDir = isRight? Vector3.right * 5 : Vector3.left * 5;gem.GetComponent<Gem>().Init(moveDir);}}
    
  • 子弹脚本:
    设置子弹基本属性(速度、销毁时间)

    public class Gem : MonoBehaviour
    {public float moveSpeed = 5f;//子弹移动方向private Vector3 moveDir;public float destroyTime = 2;private float destroyTimer;//初始化public void Init(Vector3 dir){moveDir = dir;destroyTimer = destroyTime;}void Update(){//gem子弹移动transform.Translate(moveDir * moveSpeed * Time.deltaTime, Space.World);//gem子弹销毁if (destroyTimer <= 0){Debug.Log("Gem Destroyed");Destroy(gameObject);}//gem子弹销毁计时器else{destroyTimer -= Time.deltaTime;}}
    }
    

怪物生成

基本流程

  • 确定好怪物生成的坐标点位
  • 确定好怪物生成的时间间隔(CD)
public class MonsterManager : MonoBehaviour
{//序列化(将数据可视化到unity的Inspector面板中)[System.Serializable]//怪物生成点public class MonsterSpawnPoint{//生成点public Transform spawnPoint;//怪物预制体public GameObject monsterPrefab;//生成间隔public float spawnInterval;//计时器(需要非序列化)private float spawnTimer;public void Update(float deltaTime){//更新计时器spawnTimer -= Time.deltaTime;if (spawnTimer <= 0){spawnTimer = spawnInterval;//生成怪物GameObject monster = GameObject.Instantiate(monsterPrefab);//将不同点生成的怪物归类到对应点下monster.transform.SetParent(spawnPoint);//设置怪物位置monster.transform.position = spawnPoint.position;}}}//怪物生成点数组public MonsterSpawnPoint[] spawnPoints;private void Update(){//更新所有生成点for (int i = 0; i < spawnPoints.Length; i++){spawnPoints[i].Update(Time.deltaTime);}}
}

创建MonsterManager后可以再在其下设置好预设的点位Points


怪物逻辑

移动逻辑

基本流程

  • 确定怪物移动逻辑是当玩家存在时,向玩家移动
    Player设置为单例模式

    //单例模式:通过将当前Player对象赋值给静态变量instance,确保游戏中只有一个Player实例,并且可以通过Player.instance全局访问。
    public static Player instance;//当游戏开始时,将当前Player对象设置为静态变量instance。
    //优点:无论在游戏的任何地方,我们都可以通过Player.instance来访问这个唯一的Player实例,从而更方便地进行全局访问和控制//初始化:在游戏开始前进行必要的初始化操作,确保Player对象在游戏中的唯一性和可访问性。
    private void Awake()
    {instance = this;
    }
    

    Monster检查玩家是否存在,不存在的话就不执行移动逻辑

    if (Player.instance == null) return;
    
  • 怪物执行向玩家移动的逻辑

    //利用向量知识,将怪物的方向始终对准玩家方向
    Vector3 moveDir = (Player.instance.transform.position - transform.position).normalized;
    //怪物移动
    transform.Translate(Time.deltaTime * moveSpeed * moveDir, Space.World);
    //判断怪物移动时的左右方向
    bool isRight = transform.position.x > Player.instance.transform.position.x;
    //根据移动时单独左右方向旋转贴图
    if (isRight) transform.localScale = new Vector3(-5, 5, 1);
    else transform.localScale = new Vector3(5, 5, 1);
    

受击死亡逻辑

基本流程

  • 为怪物添加HP变量,并设置好触发器事件函数并添加死亡动画事件

    public int HP;
    //动画控制器
    public Animator animator;private void OnTriggerEnter2D(Collider2D collision){if (HP == 0) return;//接触子弹if (collision.gameObject.CompareTag("Bullet")){//子弹碰撞后,怪物生命值减一,子弹消失Destroy(collision.gameObject);HP-=1;//HP归零时触发if (HP == 0){animator.SetTrigger("Death");}}}#region 动画事件//死亡动画结束private void OnDeathAnimationEnd(){//对象消亡Destroy(gameObject);}#endregion
    
  • 为怪物设置好死亡动画,并在动画最后一阵添加动画事件(选定脚本里写好的)

设置动画状态,并把条件设置为触发器(无后摇)

  • 将怪物添加上碰撞体组件,并勾选触发器选项

  • 将子弹添加刚体和碰撞体,锁定三个方向的轴并加上“Bullet”标签


鼠标指向为攻击方向

基本流程

  • 通过摄像机(Camera获取鼠标的坐标),再将角色朝向翻转逻辑和攻击方向逻辑改写

    //使用new关键字明确地表示camera字段是当前类特有的,与基类中的任何同名字段无关。
    public new Camera camera;void Update(){//获取鼠标位置Vector3 mousePos = camera.ScreenToWorldPoint(Input.mousePosition);mousePos.z = 0;Move(mousePos);Attack(mousePos);}private void Move(Vector3 mousePos){//获取输入int inputX = (int)UnityEngine.Input.GetAxisRaw("Horizontal");int inputY = (int)UnityEngine.Input.GetAxisRaw("Vertical");//设置动画bool isMoving = (inputX!= 0 || inputY!= 0);animator.SetBool("Move", isMoving);//设置角色的朝向if (mousePos.x > transform.position.x) transform.localScale = new Vector3(5, 5, 1);else if (mousePos.x < transform.position.x) transform.localScale = new Vector3(-5, 5, 1);//移动角色Vector3 moveDirection = new Vector3(inputX, inputY, 0);transform.Translate(moveDirection * moveSpace * Time.deltaTime);}private void Attack(Vector3 mousePos){//子弹冷却if (shootCDTimer > 0){shootCDTimer -= Time.deltaTime;//如果子弹冷却时间未到,则不发射子弹return;}//鼠标左键按下发射子弹,持续按下可以持续发射子弹if (Input.GetMouseButton(0)){//设置子弹冷却时间shootCDTimer = shootCD;//实例化一个Gem子弹GameObject gem = GameObject.Instantiate(gemPrefab);//设置子弹的位置gem.transform.position = gemShootPoint.position;//设置子弹的方向Vector3 moveDir = (mousePos - transform.position).normalized;gem.GetComponent<Gem>().Init(moveDir);}}
    

玩家生命值以及状态(模拟UI)

基本流程

  • 为解决人物移动时,Camera会带着UI一起翻转的问题,需要将Camare单独列出并使用脚本的方法让Camera跟随玩家视角

  • 为保证能稳定获取玩家最后一帧的位置,所以使用LateUpdate

    public Transform target;private void LateUpdate(){Vector3 pos = target.position;//避免摄像机与其他素材重叠pos.z = -10;transform.position = pos;}
    

    可新建一个CameraPoint在玩家身上,用于挂起target

  • 给玩家新建一个HP字段并定义属性,后继续设置一个HP精灵管理器以及HP状态精灵数组

        //声明一个HpSpriteRenderer字段,用于渲染角色的血条public SpriteRenderer HpSpriteRenderer;//声明一个HpSprites字段,用于存储角色的血条图片public Sprite[] HpSprites;
    //[SerializeField]:这是一个属性(Attribute),用于指示Unity在Inspector窗口中显示私有字段hp,即使它是私有的。
    //private int hp:声明一个私有的整型变量hp,用于存储角色的生命值。[SerializeField] private int hp;//声明一个公共属性HP,用于外部访问和修改私有字段hp。public int HP{//返回私有字段hp的值。get => hp;//用于设置私有字段hp的值,并在设置值时更新HpSpriteRenderer的精灵图像。set{//将传入的值value赋给私有字段hphp = value;HpSpriteRenderer.sprite = HpSprites[hp];}}private void Awake(){instance = this;//血量初始化HP = HpSprites.Length - 1;}
    
  • 在unity中拖入对应组件


玩家受伤及死亡

基本流程

  • 在怪物的脚本下设置好玩家触发到怪物后的事件

     private void OnTriggerEnter2D(Collider2D collision){        //接触玩家//如果发生碰撞的物体Tag为“Player”的话,调用对应组件的Hurt()方法if (collision.gameObject.CompareTag("Player")){collision.gameObject.GetComponent<Player>().Hurt();}}
    
  • 在玩家脚本下写好受伤方法,死亡方法以及死亡动画事件

     [SerializeField] private int hp;public int HP{get => hp;set{hp = value;HpSpriteRenderer.sprite = HpSprites[hp];//将和hp归零判断放在字段中更方便if (hp == 0){Death();}}}public void Hurt(){if (HP <= 0) return;HP-=1;}private void Death(){//触发死亡动画条件animator.SetTrigger("Death");}#region 动画事件//死亡动画结束private void OnDeathAnimationEnd(){//隐藏玩家组件gameObject.SetActive(false);}#endregion
    

    编辑好死亡动画后,在动画最后一帧设置动画事件,选定OnDeathAnimationEnd()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/790768.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RabbitMQ 队列使用基础教程

实践环境 JDK 1.8.0_121 amqp-client 5.16.0 附:查看不同版本的amqp-client客户端支持的Java JDK版本 https://www.rabbitmq.com/client-libraries/java-versions mavn settings.xml <?xml version="1.0" encoding="UTF-8" ?> <settings xsi:…

2024 年 13 个适用于 Linux 的最佳照片图像编辑器

2024 年 13 个适用于 Linux 的最佳照片图像编辑器 在本文中,我回顾了各种 Linux 发行版上可用的一些最佳照片编辑软件。这些不是唯一可用的照片编辑器,但却是 Linux 用户最流行和最常用的照片编辑器之一。 1. GIMP 首先,在列表中,我们有 GIMP,一个免费、开源、跨平台、可扩…

设置IIS支持ashx

打开【处理程序映射】 默认界面如下(是不支持处理ashx的):如果需要设置能处理ashx,需要开启ASP.NET 4.8再打开【处理程序映射】,如下:

Openshift 3.11单机版 离线安装

Openshift 3.11单机版 离线安装 ‍ 前置条件虚拟机: 建议系统内存>=6G,CPU>=4。 镜像仓库:在虚拟机上能够访问到该镜像仓库,如果没有,推荐使用harbor自建。 docker:虚拟机上需要安装docker,这里使用的是18.09版本。离线安装可参考 docker 离线安装 或自行下载rpm包…

Openshift 3

Openshift 3.11单机版 离线安装 ‍ 前置条件虚拟机: 建议系统内存>=6G,CPU>=4。 镜像仓库:在虚拟机上能够访问到该镜像仓库,如果没有,推荐使用harbor自建。 docker:虚拟机上需要安装docker,这里使用的是18.09版本。离线安装可参考 docker 离线安装 或自行下载rpm包…

类图各个箭头和符号的含义

参考资料:看懂类图和时序图案例:车的类图结构为<<abstract>>,表示车是一个抽象类; 它有两个继承类:小汽车和自行车;它们之间的关系为实现关系,使用带空心箭头的虚线表示; 小汽车为与SUV之间也是继承关系,它们之间的关系为泛化关系,使用带空心箭头的实线表…

042.CI4框架CodeIgniter,控制器过滤器Filter配合Services的使用

01、Config中的Services.php代码如下:<?phpnamespace Config;use App\Libraries\Tx_Auth; use CodeIgniter\Config\BaseService;class Services extends BaseService {//用户权限类public static function user_auth($getShared = true){echo 测试service能不能正常调用。…

第一次作业:自我介绍+软件五问

这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/CSGrade22-34这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/homework/13228这个作业的目标 初步学会使用博客园自我介绍 大家好!我是计算机学院22级计科3班的学生迪力拜尔赛买提 爱好:跑步…

机器学习之——决策树条件熵计算[附加计算程序]

0 前言本文主要介绍决策树条件熵的计算并给出若干例子帮助理解。 读者需要具备信息熵计算知识,若不了解请看:信息熵1 条件熵2 数据集 游玩数据集,请看:数据集 1.1节 3 条件熵的计算 使用所给游玩数据集。计算H(play|outlook)的条件熵(在Y随机变量为outlook条件下,X随机变量…

react创建项目常见的三大Hook

react创建项目&&常见的三大Hook 创建react脚手架项目 全局安装 create-react-app 工具: npm i -g create-react-app查看安装工具的版本号,注意V大写 create-react-app -V进入要创建的文件目录创建react项目,名为:react_project create-react-app react_project启动项…

GAugLLM论文阅读笔记

GAugLLM: Improving Graph Contrastive Learning for Text-Attributed Graphs with Large Language Models论文阅读笔记 Abstract 现存的问题: ​ 文本属性的长度和质量往往各不相同,因此很难在不改变原始语义的情况下扰乱原始文本描述。其次,虽然文本属性与图结构互为补充,…

Ceph Reef(18.2.X)之对象访问策略配置

作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任。 目录一.对象存储概述1.对象存储的访问方式2.基于http方式访问对象存储注意事项3.查看存储桶默认策略二.定制策略1.定制访问策略文件2.应用访问策略3.应用跨域规则【可选操作】三.对象存储的其他访问方式1.基于…