unity实现一个大乱斗

news2024/11/26 13:53:10

1. 游戏说明

大乱斗是一种常见的游戏模式,所有角色会进人同一个场景,玩家可以控制它们移动, 也可以让角色攻击敌

  • 打开客户端即视为进入游戏,在随机出生点刷出角色
  • 使用鼠标左键点击场景,角色会自动走到指定位置
  • 在站立状态下,点击鼠标右键可使角色发起攻击,角色会向鼠标指向的方向进行攻击
  • 每个角色默认有100滴血(hp),受到攻击会掉血,死亡后从场景消失,提示"game over"
  • 若玩家掉线,视为死亡,从场景中消失

2. 类结构设计

大乱斗游戏的核心要素之一是玩家所控制的角色,它可以行走,还可以攻击其他角色。 玩 家 可以 操 控 一 个 角 色 ,
又能够看到其他玩家操控的角 色 , 可想而知 , 这 两种 角 色 应 有 不 同 的 表 现 。 玩 家 操 控 的 角 色 是 由 玩家 驱 动 的 ( 下 称 “ 操 控 角 色 ” ), 它 接 受 鼠 标 的控 制 ; 其 他 玩 家 操 控的 角色 (下 称 “ 同步角 色” ) 是 由网 络 数 据 驱 动的 , 由 服 务端 转 发 角 色 的状 态信 息。 这两 种 角色 有 很 多共 同 点,
比 如 都 可以 行 走、 都 可以 表 现攻 击动 作 等。

可以设计图3-8所 示的 类结构,其基类BaseHuman是基础的角色类,它处理“ 操控角 色〞和“同步角色”
的一些共有功能;CtrlHluman类代表“ 操控角色”,它在BaseHluman类的基础上处理鼠标操控功能;SyncHuman
类是“同步角色”类, 它 也 继 承 自 BaseHuman , 并处理网络同步(如果有必要)。

在这里插入图片描述
2.1 BaseHuman类

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

public class BaseHuman : MonoBehaviour {
   
    //是否正在移动
	internal bool isMoving = false;
	//移动目标点
	private Vector3 targetPosition;
	//移动速度
	public float speed = 1.2f;
	//动画组件
	private Animator animator;
	//是否正在攻击
	internal bool isAttacking = false;
	internal float attackTime = float.MinValue; //最近攻击时间
	//描述
	public string desc = "";

    // Use this for initialization
	internal void Start () {
   
		animator = GetComponent<Animator>();
	}

	// Update is called once per frame
	internal void Update () {
   
		MoveUpdate();
		AttackUpdate();
	}

    //移动Update
	public void MoveUpdate(){
   
	    //判断当前是否处于行走状态,如果不是行走状态,就不须往目的地行进了
		if(isMoving == false) {
   
			return;
		}
		Vector3 pos = transform.position;
		//MoveTowards的作用是计算pos朝targetPosition方向移动一段距离后的位置
		transform.position = Vector3.MoveTowards(pos, targetPosition, speed*Time.deltaTime);
		//让角色
		transform.LookAt(targetPosition);
		if(Vector3.Distance(pos, targetPosition) < 0.05f){
   
			isMoving = false;
			animator.SetBool("isMoving", false);
		}
	}

    //移动到某处
    public void MoveTo(Vector3 pos) {
   
       targetPosition = pos; //把目的地坐标赋给targetPosition
       isMoving = true; //正在移动
       animator.SetBool("isMoving", true);
    }

    //攻击动作
	public void Attack(){
   
		isAttacking = true;
		attackTime = Time.time;
		animator.SetBool("isAttacking", true);
	}

	//攻击Update
	public void AttackUpdate(){
   
		if(!isAttacking) return;
		if(Time.time - attackTime < 1.2f) return;
		isAttacking = false;
		animator.SetBool("isAttacking", false);
	}
}

在这里插入图片描述

(1) 继承关系
BaseHuman类继承自MonoBehaviour,说明它可以作为组件挂到Gameobject身上,也说明它拥有MonoBehaviour的一些性质,比如在唤醒时会执行Awake和Start,每帧会执行一次Update。
可见继承MonoBehaviour会有Start和Update方法
(2) 移动功能
在这里插入图片描述

  • isMoving是bool型变量,指代角色是否正在移动
  • targetPosition是Vector3类型的坐标,代表角色移动的目的地。
  • MoveTo方法会把目的地的坐标赋给targetPosition,该方法给玩家指定目的地,当玩家点击鼠标时,会调用所控制角色的MoveTo方法,设置目的地坐标targetPosition和动画状态
  • MoveUpdate会让玩家一步步往目的地方向移动,它会每帧执行一次。
  • speed代表移动的速
  • 使用transform.LookAt让角色转向目标点
  • MoveUpdat e 是 一 个 被 Update调用的方 法, 所以它会每帧执行一次。 首先通 过 if (isMoving== false)判断当前是否处于行走状态,如果不是行走状态,就无须往目的地行进了; 接着通过Vector3.MoveTowards 计算新位置 ,MoveTowards的作用 是计算pos 朝 targetPosition 方向移动一段距离后的位置; 之后使用transform.Look At让角色转向目标点; 最后使用Vector3.Distance判断当前位置与目标位置的距离, 如果距离足够小,就认为角色到达了目的地,再将角色状态更改为站立(isMoving=false).

(3)动画功能
BaseHuman中定义了Animator型变量animator,它会指代角色身上的动画控制器。动画控制器中设有isMoving参数,程序通过类似"animator.SetBool(“isMoving”, false);"的语句改变动画控制器的值,从而让角色播放行走和站立两种动画。

2.2 CtrlHuman 操作角色
在这里插入图片描述

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

public class CtrlHuman : BaseHuman {
   


	// Use this for initialization
	new void Start () {
   
		base.Start();
	}
	
	// Update is called once per frame
	new void Update () {
   
		base.Update();
		//移动 判断鼠标是否被按下:参数为0表示判断鼠标左键是否被按下
		//Input.mousePosition代表当前鼠标所指的屏幕坐标
		if(Input.GetMouseButtonDown(0)){
   
            // 发出一条射线
			Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
			RaycastHit hit;
			Physics.Raycast(ray, out hit);
			//射线与场景发生碰撞(Tag为Terrain) 那么碰撞点就是角色移动的目标点
			if (hit.collider.tag == "Terrain"){
   
				MoveTo(hit.point);
				//发送协议
				string sendStr = "Move|";
				sendStr += NetManager.GetDesc()+ ",";
				sendStr += hit.point.x + ",";
				sendStr += hit.point.y + ",";
				sendStr += hit.point.z + ",";
				NetManager.Send(sendStr);
			} 
		}
		//攻击 判断鼠标右键是否被按下
		if(Input.GetMouseButtonDown(1)){
   
			if(isAttacking) return;
			if(isMoving) return;

			Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
			RaycastHit hit;
			Physics.Raycast(ray, out hit);
			if(hit.collider.tag != "Terrain") return;
			transform.LookAt(hit.point);
			Attack();
			//发送协议
			string sendStr = "Attack|";
			sendStr += NetManager.GetDesc()+ ",";
			sendStr += transform.eulerAngles.y + ",";
			NetManager.Send(sendStr);
			//攻击判定
			Vector3 lineEnd = transform.position + 0.5f*Vector3.up;
			Vector3 lineStart = lineEnd + 20*transform.forward;
			if(Physics.Linecast(lineStart, lineEnd, out hit)){
   
				GameObject hitObj = hit.collider.gameObject;
				if(hitObj == gameObject)
					return;
				SyncHuman h = hitObj.GetComponent<SyncHuman>();
				if(h == null)
					return;
				sendStr = "Hit|";
				sendStr += NetManager.GetDesc()+ ",";
				sendStr += h.desc + ",";
				NetManager.Send(sendStr);
			}

		}
	}
}

代码说明:
(1) base.xxx, new void xxx()

base 指当前类的父类,可调用父类的非私有属性和方法,代码中的base.Start 和base. Update
指代调用父类BaseHluman的Start 和Update 方法。 new用作修饰符时,new
关键字可以显式地隐藏从基类继承的成员。隐藏继承的成员 时,该成员的派生版本将替换基类版本。虽然可以在不使用new修饰符的情况下隐藏成员,
但会生成警告。

(2)判断鼠标输入

Input.GetMouseButtonDown(0)用 于判断鼠标是否被按 下:参数为0 表示判断鼠标左键 是否被按下,
参数为1表示判断鼠标右键是否被按下。 而 Input.mousePosition代表当前鼠标所指的屏幕坐标。

(3)获取点击位置

Unity3D中的Camera.ScrenPointToRay 方法能够将屏幕位置转成一条射线,只需填入屏幕坐标点 ,
该方法将返回对应的射线。 射线是在三维坐标中一个点向一 个 方 向 发 射 的 一 条线,Unity3D中可以使用Ray
和Physics.Raycast 来做射线检测。当射线射向碰撞器时 Raycast 返回true, 否则为fal se, 并且可以通过out
hi t 变量获取碰撞点。如果射线与场景发 生碰撞(Tag为Terrain),那么碰撞点就是角色移动的目标点。

2.3 syncHuman同步角色

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

public class CtrlHuman : BaseHuman {
   
	// Use this for initialization
	new void Start () {
   
		base.Start();
	}
	
	// Update is called once per frame
	new void Update () {
   
		base.Update();
		//移动
		if(Input.GetMouseButtonDown(0)){
   
			Ray ray = Camera.main

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

栈和队列(适配器模式模拟)

文章目录 声明stack的介绍queue的介绍deque双端队列简单介绍&#xff08;了解&#xff09;概述优缺点 适配器模式通过容器适配器模拟stack通过容器适配器模拟queue 总结 声明 模拟实现源代码已上传至gitee仓库&#xff1a;stack_queue_learn stack的介绍 stack文档介绍 sta…

优思学院带你走进精益生产:现场观察(Gemba Walk)的艺术

精益生产是一种管理哲学&#xff0c;其目标是在不断提高价值的同时&#xff0c;尽可能地减少浪费和缩短交付时间。实现精益生产的关键步骤之一是现场观察&#xff08;Gemba Walk&#xff09;&#xff0c;通过现场观察&#xff0c;可以深入了解生产流程&#xff0c;发现潜在的浪…

IDM2024手机版+电脑版免费高效的下载管理工具

在数字时代&#xff0c;下载管理软件已经成为我们日常工作和生活中不可或缺的工具。随着互联网的快速发展&#xff0c;我们需要下载的文件数量和大小不断增加&#xff0c;而传统的浏览器下载方式已经无法满足我们对速度和稳定性的需求。因此&#xff0c;选择一个高效的下载管理…

山东大学软件学院项目实训-创新实训-基于大模型的旅游平台(三十二)- 微服务(12)

目录 12.8 RestClient查询文档 12.8.1 快速入门 12.8.2 match&#xff0c; term&#xff0c;bool&#xff0c;range查询 12.8.3 排序和分页 12.8.4 高亮 12.8 RestClient查询文档 12.8.1 快速入门 Testvoid testMatchALL() throws IOException {// 1. 准备requestSearchReq…

服务器防漏扫,主机加固方案来解决

什么是漏扫&#xff1f; 漏扫是漏洞扫描的简称。漏洞扫描是一种安全测试方法&#xff0c;用于发现计算机系统、网络或应用程序中的潜在漏洞和安全弱点。通过使用自动化工具或软件&#xff0c;漏洞扫描可以检测系统中存在的已知漏洞&#xff0c;并提供相关的报告和建议&#xf…

推荐这3个APP,帮助你成长

扇贝阅读 当年考英语四级&#xff0c;扇贝阅读帮了很大的帮&#xff0c;这个应用我推荐给了好多同学使用&#xff0c;大家一致反馈不错。 提供很多原版的英文原著供学习&#xff0c;还自带翻译功能&#xff0c;并且提供单词本&#xff0c;遇到不懂的单词可以纪录到单词本中&am…

STM32理论 —— μCOS-Ⅲ(2/2):时间管理、消息队列、信号量、任务内嵌信号量/队列

文章目录 9. 时间管理9.1 OSTimeDly()9.2 OSTimeDlyHMSM()9.3 OSTimeDlyResume()9.4 延时函数实验 10. 消息队列10.1 创建消息队列函数OSQCreate()10.2 发送消息到消息队列函数(写入队列)OSQPost()10.3 获取消息队列中的消息函数(读出队列)OSQPend()10.4 消息队列操作实验 11. …

Fast R-CNN 与 R-CNN的不同之处

目录 一、Fast R-CNN如何生成候选框特征矩阵 二、 关于正负样本的解释 三、训练样本的候选框 四、Fast R-CNN网络架构 4.1 分类器 4.2 边界框回归器 一、Fast R-CNN如何生成候选框特征矩阵 在R-CNN中&#xff0c;通过SS算法得到2000个候选框&#xff0c;则需要进行2000…

Vulnhub-DC-1,7

靶机IP:192.168.20.141 kaliIP:192.168.20.128 网络有问题的可以看下搭建Vulnhub靶机网络问题(获取不到IP) 前言 1和7都是Drupal的网站&#xff0c;只写了7&#xff0c;包含1的知识点 信息收集 用nmap扫描端口及版本号 进入主页查看作者给的提示&#xff0c;不是暴力破解的…

开源大模型之辩:真假开源

目录 前言开源的定义什么是开源大模型&#xff1f;大模型时代首次出现闭源和开源“齐头并进”开源和闭源不是绝对对立的 大模型到底开源什么&#xff1f;传统开源软件与开源大模型的差别开源软件让开源大模型“受益匪浅” 不同大模型企业&#xff0c;开源、闭源策略不同开源…

机器学习——集成学习和梯度提升决策树

集成学习 不同的算法都可以对解决同一个问题&#xff0c;但是可能准确率不同&#xff0c;集成学习就是不同算法按照某种组合来解决问题&#xff0c;使得准确率提升。 那怎么组合算法呢&#xff1f; 自举聚合算法**&#xff08;bagging&#xff09;** 顾名思义是 自举聚合 自举…

1 IDA反汇编 今天只看看 别人是怎么防护的 软件安全

先看32位还是64位 能用32位的打开就是32位&#xff0c;否则会报错。API Monitor不改软件&#xff0c;只是看。 IDA加载 用的openssl加解密 定位&#xff1a;找到需要修改的地方 一般有提示句等 先看看自己写的&#xff1a;shiftF12 展示所有的字符串&#xff1b; 修改 或…

【通信原理】数字频带传输系统

二进制数字调制&#xff0c;解调原理&#xff1a;2ASK,2FSK 二进制数字调制&#xff0c;解调原理&#xff1a;2PSK,2DPSK 二进制数字已调制信号的功率谱 二进制数字调制系统的抗噪声性能 二进制调制系统的性能总结

总结之Spring AI(一)——使用Spring AI

前言 当前各种AI项目层出不穷&#xff0c;但绝大多数都是用python写的&#xff0c;现在Spring开源了Spring AI项目&#xff0c;让Java开发者也可以轻松给自己的springboot项目集成AI能力。目前spring AI正式版本为0.8.1&#xff0c;支持接入openAI、Ollama、Azure openAI、Hug…

手机短信验证码登录

用户需求&#xff1a; 1、用户使用手机号和短信验证码登录系统 2、未注册过的手机号再登录时实现自动注册 3、新注册的账号只有7天的使用时间&#xff0c;过期后不允许进行登录 功能需求&#xff1a; 登录页面设计 图1.手机号登录 【验证码登录】规则说明&#xff1a; 1…

【three.js】设置three.js全屏展示,并解决大小动态变化

目录 一、设置全屏 二、canvas画布宽高度动态变化 一、设置全屏 这个很简单,直接用代码读取当前全屏需要的长宽即可。 const width = window.innerWidth; //窗口文档显示区的宽度作为画布宽度 const height = window.innerHeight; //窗口文档显示区的高度作为画布高度 二、…

水帘降温水温

不同环境下的水帘啊&#xff0c;使用水温是不一样的&#xff0c;夏天使用水疗的水有两种&#xff0c;一个是常温的循环水&#xff0c;20~26左右&#xff0c;另外一个呢&#xff0c;就是深井水&#xff0c;重点是啥呢&#xff1f;就是无论我们用哪一种&#xff0c;能够把温度降到…

计算机网络(4) 最长前缀匹配(路由转发表)

一.路由转发 网络数据包IP段只包含源地址与目的地址&#xff0c;经过数据链路层包装与物理层信号形式转换&#xff0c;最终经由不同的链路节点到达目的地址。这个过程是一步一步&#xff08;hop by hop&#xff09;进行的&#xff0c;路过一个路由节点则称为一跳。每个路由节点…

绘唐一键追爆款3正式版

【绘唐2一键追爆款】 这是一个关于追求梦想的故事&#xff0c;讲述了一个普通人如何利用一键追爆款的技巧&#xff0c;成功打造自己的事业的动人故事。 主人公小明是一个市井小民&#xff0c;生活过得平凡无奇。他一直怀揣着一个梦想&#xff0c;希望能够通过自己的努力&#x…

Stable Diffusion: ControlNet Openpose

上一文已经介绍了ControlNet的安装&#xff0c;点击右边的三角箭头。 拖放原始姿态图片。 勾选“启用”&#xff0c;“完美像素模式”&#xff0c;“允许预览” 控制类型选择“OpenPose(姿态&#xff09;” 预处理器选“openpose_full”&#xff0c;会对原始姿态图片做整体分…