3D游戏设计-模型与动画

Unity 第七次作业

智能巡逻兵

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

运行截图

在这里插入图片描述

视频网址:

http://www.iqiyi.com/w_19sbavu495.html

具体模型

Player: 在这里插入图片描述
Wall: 在这里插入图片描述
Map: 在这里插入图片描述

发布订阅模式

订阅者把自己想订阅的事件注册到调度中心,当该事件触发时候,发布者发布该事件到调度中心(顺带上下文),由调度中心统一调度订阅者注册到调度中心的处理代码.
比如有个界面是实时显示天气,它就订阅天气事件(注册到调度中心,包括处理程序),当天气变化时(定时获取数据),就作为发布者发布天气信息到调度中心,调度中心就调度订阅者的天气处理程序。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HkxS0hzh-1572084218569)(asset/message.png)]
针对此游戏来讲, 我们定义两种消息, Catch与PlayerPosition, Catch用来处理Player被Monster追击到的情况, PlayerPosition用来发布Player自身的坐标信息, 从而给Monster发现并追击的机会.

源代码

player_movement.cs

管理Player的移动与旋转, 并进行消息的发布和订阅, 具体发布Catch和PlayerPosition两个消息, 当Player在运动过程中与巡逻兵发生碰撞时会触发OnCollisionEnter()函数, 进一步发布Catch消息, 通知场景控制器游戏结束. PlayerPosition消息是用来通知Monster自己的坐标位置, 从而距离小于一定值的时候Monster发现自己并开始追击.

using UnityEngine;

namespace SwordWorld
{
    public class player_movement
        : MonoBehaviour
    {
        public float walk_speed = 30f;
        public float run_speed = 30f;


        private Vector3 movement;
        private Animator animator;
        private Rigidbody playerRigidbody;

        // rotate
        public float turnSmoothing = 3.0f;
        private Transform cameraTransform;
        private bool isWalk;
        private bool isRun;
        private float h;
        private float v;

        // jump
        public float jumpHeight = 5.0f;
        public float jumpCooldown = 1.0f;
        private bool isJump;
        
        void Awake()
        {
            // Set up references.
            animator = GetComponent<Animator>();
            playerRigidbody = GetComponent<Rigidbody>();

            cameraTransform = Camera.main.transform;
        }

        void Update()
        {
            h = Input.GetAxisRaw("Horizontal");
            v = Input.GetAxisRaw("Vertical");
            isJump = Input.GetButtonDown("Jump");
            isWalk = Mathf.Abs(h) > 0.1 || Mathf.Abs(v) > 0.1;

            if (isWalk)
            {
                if (isRun)
                {
                    isRun = !Input.GetButtonUp("Run");
                }
                else
                {
                    isRun = Input.GetButtonDown("Run");
                }
            }
            else
            {
                isRun = false;
            }
        }

        void FixedUpdate()
        {
            // Move the player around the scene.
            Move(h, v);

            // Turn the player to face the mouse cursor. 
            Rotate(h, v);

            // Jump
            Jump(h, v);
        }

        void Move(float h, float v)
        {
            float speed = isRun ? run_speed : walk_speed;

            // Set the movement vector based on the axis input.
            movement.Set(h, 0.0f, v);

            // Normalise the movement vector and make it proportional to the speed per second.
            movement = movement.normalized * speed * Time.deltaTime;

            // Move the player to it's current position plus the movement.
            playerRigidbody.MovePosition(transform.position + movement);

            // Animator
            {
                if (isRun)
                {
                    animator.SetBool("IsRun", isRun);
                }
                else
                {
                    animator.SetBool("IsRun", isRun);
                    animator.SetBool("IsWalk", isWalk);
                }
            }
        }

        void Jump(float h, float v)
        {
            if (isJump)
            {
                animator.SetTrigger("Jump");
                playerRigidbody.velocity = new Vector3(0, jumpHeight, 0);
            }
        }

        Vector3 Rotate(float h, float v)
        {
            Vector3 forward = cameraTransform.TransformDirection(Vector3.forward);
            forward = forward.normalized;

            Vector3 right = new Vector3(forward.z, 0, -forward.x);

            Vector3 targetDirection;
            targetDirection = forward * v + right * h;

            if ((isWalk && targetDirection != Vector3.zero))
            {
                Quaternion targetRotation = Quaternion.LookRotation(targetDirection, Vector3.up);

                Quaternion newRotation = Quaternion.Slerp(GetComponent<Rigidbody>().rotation, targetRotation, turnSmoothing * Time.deltaTime);

                // TODO:不知为毛,Rigid 的约束不起作用,只能手动设置为 0 
                newRotation.x = 0f;
                newRotation.z = 0f;
                GetComponent<Rigidbody>().MoveRotation(newRotation);
            }

            return targetDirection;
        }
    }
}
UI.cs

UI部分主要负责管理Score

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UI : MonoBehaviour
{
    public static int score = 0;
    private GUIStyle style;
    public static bool is_end = false;
    // Start is called before the first frame update
    void Start()
    {
        style = new GUIStyle();
        style.fontSize = 30;
    }

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

    private void OnGUI() {
        if (is_end) {
            GUI.Label(new Rect(Screen.width / 4, Screen.height / 4, 200, 100), "Game Over, your score is : " + score, style);
        } else {
            GUI.Label(new Rect(Screen.width / 10, Screen.height / 10, 200, 100), "Score: " + score, style);
        }
    }
}
MonsterMove.cs

MonsterMove脚本负责管理Monster的移动, 并且订阅PlayerPosition消息, 从而获取Player当前的坐标信息, 当距离小于一定值的时候就会触发追击函数, 也就是Monster发现了Player, 并加快速度进行追击.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MonsterMove : MonoBehaviour
{
    private float speed = 3.0f;
    private float mtime = 3.0f;

    private float x, z;
    private Vector3 vec;
    private bool is_run = true;

    private bool is_chase = false;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        vec = this.gameObject.transform.position;
        mtime += Time.deltaTime;
        if (getDistance(Judge.x, Judge.z, vec.x, vec.z) < 30) {
            is_chase = true;
            mtime = 3.0f;
            speed = 11.0f;
            float theta = Mathf.Atan(Mathf.Abs(vec.z - Judge.z) / Mathf.Abs(vec.x - Judge.x));
            if (vec.x < Judge.x) {
                this.gameObject.transform.Translate(Vector3.right * speed * Time.deltaTime * Mathf.Cos(theta));
            } else {
                this.gameObject.transform.Translate(Vector3.left * speed * Time.deltaTime * Mathf.Cos(theta));
            }
            if (vec.z < Judge.z) {
                this.gameObject.transform.Translate(Vector3.forward * speed * Time.deltaTime * Mathf.Sin(theta));
            } else {
                this.gameObject.transform.Translate(Vector3.back * speed * Time.deltaTime * Mathf.Sin(theta));
            }
            this.transform.rotation = Quaternion.Euler(new Vector3(0, 0, 0));
            return;
        }else if(mtime >= 3) {
            if (is_chase) {
                is_chase = false;
                if(!UI.is_end)
                    UI.score += 1;
            }
            speed = 3.0f;
            mtime -= 3;
            float ori_x = vec.x, ori_z = vec.z;
            float x_min = vec.x - 20;
            float x_max = vec.x + 20;
            float z_min = vec.z - 20;
            float z_max = vec.z + 20;
            x = Random.Range(x_min, x_max);
            while(Mathf.Abs(x - ori_x) < 10) {
                x = Random.Range(x_min, x_max);
            }
            z = Random.Range(z_min, z_max);
            while (Mathf.Abs(z - ori_z) < 10) {
                z = Random.Range(z_min, z_max);
            }
        }
        if(x < vec.x) {
            this.gameObject.transform.Translate(Vector3.right * speed * Time.deltaTime);
        } else {
            this.gameObject.transform.Translate(Vector3.left * speed * Time.deltaTime);
        }
        if(z < vec.z) {
            this.gameObject.transform.Translate(Vector3.forward * speed * Time.deltaTime);
        } else {
            this.gameObject.transform.Translate(Vector3.back * speed * Time.deltaTime);
        }
        this.transform.rotation = Quaternion.Euler(new Vector3(0, 0, 0));
    }

    private void OnCollisionEnter(Collision collision) {
        
    }

    float getDistance(float x1, float y1, float x2, float y2) {
        return Mathf.Sqrt(Mathf.Pow(Mathf.Abs(x1 - x2), 2) + Mathf.Pow(Mathf.Abs(y1 - y2), 2));
    }
}
Judge.cs

Judge脚本与场景控制器协同负责判断游戏的结束.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Judge : MonoBehaviour
{
    public static float x;
    public static float z;
    private int count = 0;
    // Start is called before the first frame update
    void Start()
    {
        x = this.gameObject.transform.position.x;
        z = this.gameObject.transform.position.z;
    }

    // Update is called once per frame
    void Update()
    {
        x = this.gameObject.transform.position.x;
        z = this.gameObject.transform.position.z;
    }

    private void OnCollisionEnter(Collision collision) {
        string str = collision.gameObject.name;
        if (getSameCount(str, "Cylinder") >= 5)
            UI.is_end = true;
    }

    private int getSameCount(string str1, string str2) {
        int len = str1.Length > str2.Length ? str2.Length : str1.Length;
        int count = 0;
        for(int i = 0; i < len; ++i) {
            if (str1[i] == str2[i]) ++count;
            else return count;
        }
        return count;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
传说中的龙书是也。。。 最好最新的DirectX游戏开发入门书籍 英文版+中文版+源代码 打包 非常适合初学者 内容提要 -------------------------------------------------------------------------------- 本书主要介绍如何使用DirectX 9.0开发交互式3D图形程序,重点是游戏开发。全书首先介绍了必要的数学工具,然后讲解了相关的3D概念。其他主题几乎涵盖了Direct3D中的所有基本运算,例如图元的绘制、光照、纹理、Alpha融合、模板,以及如何使用Direct3D实现游戏中所需的技术。介绍顶定点着色器和像素着色器的章节(包含了效果框架和新的高级着色语言的内容)对这些关键运算进行了较为集中的讨论。 本书内容深入浅出,内容广泛,可供从事3D游戏程序设计、可视化系统设计或其他图形应用程序开发的开发人员和大中专院校学生参考,也极适合各种游戏开发培训机构作为Direct3D编程的培训教程。 目录 -------------------------------------------------------------------------------- 第Ⅰ部分 基础知识 必备的数学知识\t 3D空间中的向量\t 矩阵\t\t 基本变换\t 平面(选读)\t 射线(选读)\t 小结\t\t 第Ⅱ部分 Direct3D基础 第1章 初始化Direct3D 1.1 Direct3D概述\t 1.2 COM(组件对象模型)\t 1.3 预备知识\t 1.4 Direct3D的初始化\t 1.5 例程:Direct3D的初始化 1.6 小结\t 第2章 绘制流水线\t 2.1 模型表示\t 2.2 虚拟摄像机 2.3 绘制流水线 2.4 小结\t 第3章 Direct3D中的绘制\t 3.1 顶点缓存与索引缓存 3.2 绘制状态\t 3.3 绘制的准备工作\t 3.4 使用顶点缓存和索引缓存进行绘制\t 3.5 D3DX几何体 3.6 例程:三角形、立方体、茶壶、D3DXCreate* 3.7 小结\t 第4章 颜色\t 4.1 颜色表示 4.2 顶点颜色 4.3 着色\t 4.4 例程:具有颜色的三角形\t 4.5 小结\t 第5章 光照\t 5.1 光照的组成\t 5.2 材质\t 5.3 顶点法线\t 5.4 光源\t 5.5 例程:光照 5.6 一些附加例程\t 5.7 小结\t 第6章 纹理映射 6.1 纹理坐标\t 6.2 创建并启用纹理\t 6.3 纹理过滤器 6.4 多级渐进纹理 6.5 寻址模式 6.6 例程:纹理四边形 6.7 小结\t 第7章 融合技术\t 7.1 融合方程\t 7.2 融合因子 7.3 透明度 7.4 用DirectX Texture Tool创建Alpha通道\t 7.5 例程:透明效果\t 7.6 小结\t 第8章 模板\t 8.1 模板缓存的使用\t 8.2 例程:镜面效果\t 8.3 例程:Planer Shadows\t 8.4 小结\t 第Ⅲ部分 Direct3D的应用 第9章 字体\t 第10章 网格(一)\t 第11章 网格(二)\t 第12章 设计一个灵活的Camera类 第13章 地形绘制基础\t 第14章 粒子系统\t 第15章 拾取\t 第Ⅳ部分 着色器和效果 第16章 高级着色语言(HLSL)入门\t 第17章 顶点着色器入门\t 第18章 像素着色器入门\t 第19章 效果框架\t 附录 Windows编程入门\t 参考文献 作者介绍 -------------------------------------------------------------------------------- Prank Luna是Hero lnteractive的程序员,从事交互式3D图形编程已有八年多。他最早接触DirectX可以追溯到DirectX5发布之时,目前居住在加州的洛杉矶市。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值