模型与动画作业

2023-11-01

一、智能巡逻兵

游戏设计要求:

  • 创建一个地图和若干巡逻兵(使用动画);
  • 每个巡逻兵走一个3~5个边的凸多边型,位置数据是相对地址。即每次确定下一个目标位置,用自己当前位置为原点计算;
  • 巡逻兵碰撞到障碍物,则会自动选下一个点为目标;
  • 巡逻兵在设定范围内感知到玩家,会自动追击玩家;
  • 失去玩家目标后,继续巡逻;
  • 计分:玩家每次甩掉一个巡逻兵计一分,与巡逻兵碰撞游戏结束;

程序设计要求:

  • 必须使用订阅与发布模式传消息
    • subject:OnLostGoal
    • Publisher: ?
    • Subscriber: ?
  • 工厂模式生产巡逻兵
  • 友善提示1:生成 3~5个边的凸多边型
    • 随机生成矩形
    • 在矩形每个边上随机找点,可得到 3 - 4 的凸多边型
    • 5 ?
  • 友善提示2:参考以前博客,给出自己新玩法

参考之前博客的UML类图,如下:

 

接下来我们看订阅和发布模式。订阅和发布模式是指发布者,即消息的发送者不会将消息直接发送给订阅者,即消息的接受者。 发布者和订阅者不知道彼此的存在。具体的订阅和发布模式的模型为:发布者publisher为时间或消息的拥有者,主题subject表示消息的发布媒体,接收器handle表示处理消息的方法,订阅者subscriber表示对主题感兴趣的人。

订阅与发布模式:

 

然后我们看代码的具体实现。

首先,我们需要实现一个GameEventManager,从而实现对游戏事件消息的传递。若玩家成功逃脱一次,则分数加一;若玩家被逮到,则游戏结束,具体如下:

public class GameEventManager : MonoBehaviour
{
    //分数变化
    public delegate void ScoreEvent();
    public static event ScoreEvent ScoreChange;
    //游戏结束变化
    public delegate void GameoverEvent();
    public static event GameoverEvent GameoverChange;

  

    //玩家逃脱
    public void PlayerEscape()
    {
        if (ScoreChange != null)
        {
            ScoreChange();
        }
    }
    //玩家被捕
    public void PlayerGameover()
    {
        if (GameoverChange != null)
        {
            GameoverChange();
        }
    }
    
}

然后,用OnEnable和OnDisable表示事件的开始和结束。

void OnEnable(){
        GameEventManager.addScore += ScoreChange;
        GameEventManager.GameOver += GameoverChange;
    }
    void OnDisable(){
        GameEventManager.addScore -= ScoreChange;
        GameEventManager.GameOver -= GameoverChange;
    }
    

接下来我们来看玩家预设,如下:

 

对于玩家最重要的就是都对玩家的控制。其中首先需要实现的是玩家的移动和旋转。具体如下:

public void PlayerMove(float pos_X, float pos_Z){
        if(!game_over && player != null){
            if (pos_X != 0 || pos_Z != 0){
                player.GetComponent<Animator>().SetBool("run", true);
            }
            else{
                player.GetComponent<Animator>().SetBool("run", false);
            }
   
            player.transform.Translate(0, 0, pos_Z * 5f * Time.deltaTime);
            player.transform.Rotate(0, pos_X*1.5f, 0);
            player.transform.Translate(pos_X * 5f * Time.deltaTime, 0, 0);
            
         
            if (player.transform.localEulerAngles.x != 0 || player.transform.localEulerAngles.z != 0){
                player.transform.localEulerAngles = new Vector3(0, player.transform.localEulerAngles.y, 0);
            }
            if (player.transform.position.y != 0){
                player.transform.position = new Vector3(player.transform.position.x, 0, player.transform.position.z);
            }
        }
    }

然后是检测玩家与巡逻兵碰撞的PlayCollide,来触发游戏结束的相应条件,具体如下:

public class PlayerCollide : MonoBehaviour
{

    void OnCollisionEnter(Collision other)
    {
        //当玩家与侦察兵相撞
        if (other.gameObject.tag == "Player")
        {
            other.gameObject.GetComponent<Animator>().SetTrigger("death");
            this.GetComponent<Animator>().SetTrigger("shoot");
            Singleton<GameEventManager>.Instance.PlayerGameover();
        }
    }
}

接下来我们看巡逻兵的预设。同样需要添加一个刚体,并需要添加一个碰撞器来检测与玩家的碰撞。

我们通过工厂来产生巡逻兵,通过工厂模式实现巡逻兵的初始位置、状态等的设定:

public class PropFactory : MonoBehaviour
{
    private GameObject patrol = null;                              //巡逻兵
    private List<GameObject> used = new List<GameObject>();        //正在被使用的巡逻兵
   
    private Vector3[] vec = new Vector3[9];                        //保存每个巡逻兵的初始位置

    public FirstSceneController sceneControler;                    //场景控制器

    public List<GameObject> GetPatrols()
    {
        int[] pos_x = { -6, 4, 13 };
        int[] pos_z = { -4, 6, -13 };
        int index = 0;
        //生成不同的巡逻兵初始位置
        for(int i=0;i < 3;i++)
        {
            for(int j=0;j < 3;j++)
            {
                vec[index] = new Vector3(pos_x[i], 0, pos_z[j]);
                index++;
            }
        }
        for(int i=0; i < 9; i++)
        {
            patrol = Instantiate(Resources.Load<GameObject>("Prefabs/Patrol"));
            patrol.transform.position = vec[i];
            patrol.GetComponent<PatrolData>().sign = i + 1;
            patrol.GetComponent<PatrolData>().start_position = vec[i];
            used.Add(patrol);
        }   
        return used;
    }


    
    public void StopPatrol()
    {
        //切换所有侦查兵的动画
        for (int i = 0; i < used.Count; i++)
        {
            used[i].gameObject.GetComponent<Animator>().SetBool("run", false);
        }
    }
}

然后是巡逻兵的追随玩家的动作的实现:

public class PatrolFollowAction : SSAction
{
    private float speed = 2f;            //跟随玩家的速度
    private GameObject player;           //玩家
    private PatrolData data;             //侦查兵数据

    private PatrolFollowAction() { }
    public static PatrolFollowAction GetSSAction(GameObject player)
    {
        PatrolFollowAction action = CreateInstance<PatrolFollowAction>();
        action.player = player;
        return action;
    }

    public override void Update()
    {
        if (transform.localEulerAngles.x != 0 || transform.localEulerAngles.z != 0)
        {
            transform.localEulerAngles = new Vector3(0, transform.localEulerAngles.y, 0);
        }
        if (transform.position.y != 0)
        {
            transform.position = new Vector3(transform.position.x, 0, transform.position.z);
        }
         
        Follow();
        //如果侦察兵没有跟随对象,或者需要跟随的玩家不在侦查兵的区域内
        if (!data.follow_player || data.wall_sign != data.sign)
        {
            this.destroy = true;
            this.callback.SSActionEvent(this,1,this.gameobject);
        }
    }
    public override void Start()
    {
        data = this.gameobject.GetComponent<PatrolData>();
    }
    void Follow()
    {
        transform.position = Vector3.MoveTowards(this.transform.position, player.transform.position, speed * Time.deltaTime);
        this.transform.LookAt(player.transform.position);
    }
}

最后是巡逻兵的碰撞检测:

public class PatrolCollide : MonoBehaviour
{
    void OnTriggerEnter(Collider collider)
    {
        if (collider.gameObject.tag == "Player")
        {
            //玩家进入侦察兵追捕范围
            this.gameObject.transform.parent.GetComponent<PatrolData>().follow_player = true;
            this.gameObject.transform.parent.GetComponent<PatrolData>().player = collider.gameObject;
        }
    }
    void OnTriggerExit(Collider collider)
    {
        if (collider.gameObject.tag == "Player")
        {
            this.gameObject.transform.parent.GetComponent<PatrolData>().follow_player = false;
            this.gameObject.transform.parent.GetComponent<PatrolData>().player = null;
        }
    }
}

游戏运行界面如下:

​​​​​​​

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

模型与动画作业 的相关文章

  • JAVA TCP客户端和服务器端简单实例

    客户端 package com example demo import java io BufferedReader import java io InputStreamReader import java io PrintWriter i
  • 详解Java中的byte类型(补充内容)

    写在前面 大家有时候可能会对Java中出现的byte类型有些疑惑 今天就来内化这些知识点 这个算是对其他博客的一个补充 内容很少 byte 在Java中 byte占据一个字节 也就是8的bite位 public static void ma
  • Kaiwii

    http blog csdn net kaiwii article details 7478038
  • qt 16进制字符串 转换为 二进制 字节流

    代码 include
  • 找出10个被打乱的数中被拿出的一个数

    include
  • RuoYi-弹出新窗口选择数据回显到父页面

    这里只贴出关键代码 其他代码需要自行编写 返回值处理根据实际需求来 目前是只取第一条 因为选择页面是单选行 表单页面新加方法 选择社区 function selectCommunity var url ctx community selec
  • 深度

    解码区块链 专题文章三 区块链的安全基础架构及构想 近期 国家发改委明确 区块链 被纳入新基建定义和范围 作为一项能够打通各个技术及领域的基础技术 区块链被认为将在各行业深度融合 新领域拓展 新场景新应用开发等方面潜力无限 解码区块链 内容
  • js 小技巧 ( 根据不同的状态生成不同的颜色和状态 )

    HTML 解决办法 动态绑定 color 然后 根据 三元表达式 进行处理 js 解决办法 动态绑定 color 然后 根据在每个数据的后面添加color属性 可能有的人会问vueb不能用不然不会双向绑定 确实vue要使用vueset 但是
  • 他人工作多年后的总结

    1 找一个好公司 精通至少一门语言及其框架 专注做5到10年 先有深度再有广度 不要为了高工资过早转向管理角色 2 从长远来看 拥有个人项目 阅读 写博客和参加访谈都会有助于你成为一个更好的开发人员 3 成为开发者社区的一部分 努力参加线上
  • qt写C++(引用的妙处,内联函数)

    首先看什么是引用 引用和取地址很像 容易混淆 单独出现 a就是对a这个变量取地址 如果是int a 就是声明这是一个引用 引用 include
  • 基于SpringBoot+redis实现一个简单的点赞功能

    点赞操作比较频繁 而且比较随意 所以数据变更很快 如果用mysql 会对mysql产生很大的压力 于是决定使用Redis 防止数据丢失 所以会定期将数据持久化同步到mysql中 一 Redis 缓存设计及实现 1 1 Redis 安装及运行
  • mysql约束之_外键约束 foreign key

    外键约束 foreign key 创建一个员工表employee 员工编号id 员工的姓名name 部门名称dept name 员工所在的地址address CREATE TABLE employee id INT PRIMARY KEY
  • R语言学习笔记

    参考 W N Venables D M Smith and the R DCT Introduction to R Notes on R A Programming Environment for Data Analysis and Gra
  • java集合Map介绍及具体使用

    目录 Map 双例集合 存储 键值对 key value 的数据 1 基本介绍 2 HashMap 2 1源码介绍 2 2 HashMap源码中的重要常量 2 3面试题 3 LinkHashMap 3 1LinkHashMap源码分析 4
  • Pandas数据处理

    数据预览 首先 调用read excel 方法读取数据 import pandas as pd df pd read excel data xlsx df 姓名 班级 语文 数学 0 张三 一班 99 90 1 李四 一班 78 NaN 2
  • 【从零开始学c++】———模拟实现string类(常用接口的实现)

    string 1 前言 2 string类常用接口实现 3 总结 1 前言 之前学到了string类常用接口的后 我很好奇string类在底层是怎样实现的 在由之前学习到c 有关的之后 所以我打算模拟实现一下string类常用的接口 以便加
  • Allegro学习笔记

    1 用Allegro进行PCB设计 文件的后缀名是 brd 2 双击 brd无法打开该文件 必须在Allegro里面File Open中进行打开
  • 《代码大全2》第5章 软件构建中的设计

    目录 前言 本章主题 5 1 设计中的挑战 5 1 1 设计在软件构建中所处的角色 5 1 2 设计是一个险恶的问题 5 2 关键的设计概念 5 2 1 软件的首要技术使命 管理复杂度 1 管理复杂度的重要性 5 2 2 理想的设计特征 5
  • threeJs着色器ShaderMaterial以及统一着色语言GLSL语法基本介绍

    一 着色器材质ShaderMaterial的基本使用 废话不多讲先来看案例 console log 着色器入门 引入three js import as THREE from three 引入OrbitControls控制器 import
  • RuntimeError: cuDNN error: CUDNN_STATUS_NOT_SUPPORTED.

    原因 batch size太大了 说起来我也觉得挺奇怪 bs太大为什么不报错out of memory而是报了这么一个牛头不对马嘴的错误 不过因为我这个环境已经跑了很多模型都没有问题 因此不是cudnn和cuda版本对应问题 将bs调小一半

随机推荐

  • 常用Linux发行版镜像源配置

    最近研究Linux 试了一些Linux发行版 但是大多数发行版的软件源速度都不是很理想 所以我这里干脆做了一个收集 把我用过的一些常用发行版的软件源设置方法做个总结 大家也可以做个参考 Ubuntu 18 04 18 04是目前Ubuntu
  • unity Animation和Animator动画的暂停和继续播放

    1 利用Animator组件实现暂停和继续播放自己创建的Animation动画 需要按以下顺序操作 在需要播放动画的物体身上添加Animator组件 在Project视图下创建AnimatorController并拖入到Animator组件
  • 【vue3+ts+ant】a-table的column绑定点击事件的两种方式

    需求 给标题这一列的数据绑定点击事件 实现交互 第一种 在dom里面插入标签 并绑定点击事件
  • 【牛客网 - 华为机试 - HJ85 最长回文子串】

    描述 给定一个仅包含小写字母的字符串 求它的最长回文子串的长度 所谓回文串 指左右对称的字符串 所谓子串 指一个字符串删掉其部分前缀和后缀 也可以不删 的字符串 数据范围 字符串长度 进阶 时间复杂度 O n O n 空间复杂度 O n O
  • Java编码规范

    目录 1 代码规范 2 1 1 注释规范 2 1 1 1 页头注释
  • redux之react-redux实现原理

    Redux Flow 一 介绍 一 redux 1 reducer念 reducer就是一个纯函数 接收旧的state和action 返回新的state previousState action gt newState 名字由来 Array
  • Java 实现下载文件工具类

    package com liunian utils import lombok SneakyThrows import javax servlet ServletOutputStream import javax servlet http
  • 力扣每日一题——四数相加Ⅱ

    题目链接 class Solution public 将四个组分为两组 即时间复杂度n 4 gt 2 n 2 int fourSumCount vector
  • 服务器域名修改,服务器修改域名

    服务器修改域名 内容精选 换一换 华为云帮助中心 为用户提供产品简介 价格说明 购买指南 用户指南 API参考 最佳实践 常见问题 视频帮助等技术文档 帮助您快速上手使用华为云服务 您可以通过华为云的域名注册服务管理您的域名 如表1所示 服
  • 无法连接imessages信息服务器,如何屏蔽imessage广告 iPhone怎么屏蔽iMessages广告【详解】...

    很多苹果设备用户都会用到iMessages 苹果设备之间聊天很方便 不过iMessages广告却是一个神烦的存在 怎么屏蔽iMessages广告 下面IT百科小编和大家分享几种屏蔽iMessages广告的方法 大家可以根据自己的使用习惯选择
  • QWidget的背景颜色和背景图片的设置

    首先设置autoFillBackground属性为真 然后定义一个QPalette对象 设置QPalette对象的背景属性 颜色或图片 最后设置QWidget对象的Palette 实例 QWidget widget new QWidget
  • web基础学习笔记(九)之节点常用属性和方法

    节点常用属性和方法 getElementsByTagName 获取当前节点的指定标签名孩子节点 gappendChild oChildNode 添加一个子节点 oChildNode是要添加的孩子节点 属性 childNodes 获取当前节点
  • Docker---本地镜像发布到阿里云

    本地镜像发布到阿里云 1 准备前提 2 以当前运行运行的mycentos运行实例 以它为模板commit一个新的mycentos镜像 3 将本地镜像推送到阿里云 3 1 本地镜像素材原型 3 2 登录阿里云开发者平台创建镜像仓库 3 2 1
  • jQuery基本筛选器

    3 jQuery基本筛选器 3 1 first 获取第一个元素 用法 ul li list item 1 li li list item 2 li li list item 3 li li list item 4 li li list it
  • https网络编程——SSL的加密和解密过程

    参考 SSL的加密和解密过程 地址 https qingmu blog csdn net article details 108214105 spm 1001 2014 3001 5502 目录 现在的加密 解密技术主要有三种 对称加密 非
  • 设置EntityFramework中decimal类型数据精度问题(EF默认将只会保留到2为精度)

    原文 设置EntityFramework中decimal类型数据精度 EF中默认的decimal数据精度为两位数 当我们数据库设置的精度大于2时 EF将只会保留到2为精度 e g 2 19990将会被保存为2 20 1 解决方案一是网上找到
  • js作用域、闭包和浏览器渲染原理

    一 js作用域 变量的作用域是指变量在整个程序中作用 可访问 的范围 1 作用域的类型 三个类型 全局作用域 局部作用域 函数作用域 块级作用域 ES6新增 1 全局作用域 如果一个变量为全局作用域 那么这个变量在程序的任意位置都可以访问
  • 主流显卡Linux系统驱动安装--intel、ATi篇

    Intel 集成显卡的Linux驱动安装 目前使用Intel 集成显卡的计算机主要集中在中低端商务台式机和中低端笔记本电脑 这里介绍一下Linux下显卡驱动安装方法 I ntel针对集成显示芯片提供了两种驱动程序 i915Graphics和
  • BigInteger和BigDecimal的使用

    1 BigInteger类的常用方法 java math BigInteger类表示一个超大的整数 而且支持任意精度整数的四则运算 加减乘除 常用方法 方法 含义 public BigInteger String val 将 BigInte
  • 模型与动画作业

    一 智能巡逻兵 游戏设计要求 创建一个地图和若干巡逻兵 使用动画 每个巡逻兵走一个3 5个边的凸多边型 位置数据是相对地址 即每次确定下一个目标位置 用自己当前位置为原点计算 巡逻兵碰撞到障碍物 则会自动选下一个点为目标 巡逻兵在设定范围内