【制作100个unity游戏之28】花半天时间用unity复刻童年4399经典小游戏《黄金矿工》(附带项目源码)

最终效果

在这里插入图片描述

文章目录

  • 最终效果
  • 前言
  • 素材
  • 模拟绳子
  • 钩子来回摆动
  • 发射回收钩子方法
  • 发射钩子
  • 回收钩子
  • 勾取物品
  • 随机生成物品
  • 其他
  • 源码
  • 完结

前言

在游戏发展史上,有些游戏以其简单而耐玩的特性,深深地烙印在了玩家的记忆中。《黄金矿工》就是其中之一,它曾经在4399等游戏平台上掀起了一股游戏热潮。这款游戏不仅给无数玩家带来了欢乐,还让他们体验到了挖掘金矿的刺激与乐趣。

在这个项目中,我们将花费半天的时间,利用Unity引擎,重新打造这款经典小游戏。通过复刻《黄金矿工》,我们不仅是在向童年的回忆致敬,更是在挖掘游戏设计的精髓。在这个过程中,我们将学习如何实现游戏的核心玩法,设计简洁而有效的游戏机制。

本项目不仅仅是一个技术实践的机会,更是一个寻找游戏乐趣的旅程。无论是对于游戏开发初学者,还是对于那些怀念童年经典的老玩家,都将在这个项目中找到共鸣。希望通过这个项目,能够唤起你心中那份对于游戏的热爱与回忆,让我们一起重温那段美好的游戏时光。

素材

链接:https://pan.baidu.com/s/1bzOPsIQ3mtccH4mCm8bMzg?pwd=es5a
提取码:es5a

模拟绳子

黄金矿工游戏中,玩家通过按键操作并发射钩子来挖取金矿,钩子与绞盘之间有一条绳子进行连接,这条绳子我们使用Unity提供的LineRenderer组件来进行实现。

我们拖入钩子图片,并在上面添加LineRenderer组件,然后在Materials选项中选择默认的精灵图材质(Sprites-Default),然后将Order in Layer选项修改为1,或者降低北京图的排序,防止被背景2D物体遮挡。其中,Positions选项是用来设置线段的2点,LineRenderer组件会在游戏运行时自动在2点之间进行连线。而我们也是在代码中动态修改这2点的值,来实现绳子的效果。大致设定如图:
在这里插入图片描述
接下来,在绞盘的位置新建一个空物体,用于确定线段的起点。然后在代码中更新Positions选项中点的位置即可。代码如下:

public class Hook : MonoBehaviour {public Transform startTrans;    //起始点LineRenderer lineRenderer;void Start() {lineRenderer = GetComponent<LineRenderer>();lineRenderer.startWidth = 0.1f;//修改线条宽度}void Update() {UpdataLine();}public void UpdataLine(){//设置线条2点的位置lineRenderer.SetPosition(0, startTrans.position);lineRenderer.SetPosition(1, transform.position);}
}

效果
在这里插入图片描述

钩子来回摆动

游戏中,钩子总是绕着绞盘来进行旋转。使用RotateAround这个函数就可轻松解决,难点是如何限制钩子只在下方进行旋转操作,而不会旋转到上方。此处,我们使用向量之间的夹角来进行判断,钩子是否旋转出边界。

修改Hook代码

//定义旋转方向枚举
public enum RotaDir
{left,right,
}public RotaDir nowDir;    //玩家当前的旋转方向
public float angleSpeed;  //旋转速度
public void PlayRotate()
{float rightAngle = Vector3.Angle(transform.up, Vector3.right);//计算玩家前进方向与Right的夹角if (nowDir == RotaDir.left){if (rightAngle < 170){   //在可旋转范围内按当前方向继续旋转transform.RotateAround(startTrans.position, Vector3.forward, angleSpeed * Time.deltaTime);}else{nowDir = RotaDir.right;//超出范围,改变方向进行旋转}}else{if (rightAngle > 10){transform.RotateAround(startTrans.position, Vector3.forward, -angleSpeed * Time.deltaTime);}else{nowDir = RotaDir.left;}}
}

效果
在这里插入图片描述

发射回收钩子方法

钩子的朝向总是自己的Up轴的反方向。那么移动的方向也是如此。只要一直朝这个方向移动就行了,返回也是同样的道理。代码如下:

public float moveSpeed;public void PlayMoveForward()//前向移动
{transform.position += transform.up * -1 * moveSpeed * Time.deltaTime;
}
public void PlayBackMove()//返回移动
{transform.position += transform.up * moveSpeed * Time.deltaTime;
}

发射钩子

修改Hook,这里定义触摸屏幕,按s或者下按键发射钩子

public bool isFire;
public bool isBack;
public Vector3 playStartPoint;
public float moveSpeed;
public float startSpeed;void Update()
{if (Input.GetKeyDown(KeyCode.S) || Input.GetKeyDown(KeyCode.DownArrow)){if (!isFire){isFire = true;playStartPoint = transform.position;}}// 检测触摸输入if (Input.touchCount > 0){Touch touch = Input.GetTouch(0); // 获取第一个触摸点// 如果触摸开始if (touch.phase == TouchPhase.Began){if (!isFire){isFire = true;playStartPoint = transform.position;}}}if (isFire && !isBack){PlayMoveForward();}else if (isFire && isBack){PlayBackMove();}if (!isFire){moveSpeed = startSpeed;PlayRotate();}UpdataLine();
}

效果
在这里插入图片描述

回收钩子

目前如果不做限制,钩子肯定会无限发射出去,最简单的限制方法就是定义触发器边界,钩子触碰返回即可
在这里插入图片描述
修改Hook

public void PlayBackMove()//返回移动
{transform.position += transform.up * moveSpeed * Time.deltaTime;if (transform.position.y >= playStartPoint.y){transform.position = playStartPoint;isFire = false;isBack = false;}
}private void OnTriggerEnter2D(Collider2D other)
{if (other.CompareTag("Boundary")){isBack = true;}
}

效果
在这里插入图片描述

勾取物品

public GameObject item;public void PlayBackMove()//返回移动
{transform.position += transform.up * moveSpeed * Time.deltaTime;if (transform.position.y >= playStartPoint.y){isFire = false;isBack = false;if (item){UIManager.Instance.SetScore(item.GetComponent<Item>().money);Destroy(item);item = null;//加钱}}
}private void OnTriggerEnter2D(Collider2D other)
{if (other.CompareTag("Boundary")){isBack = true;}if (other.CompareTag("Item") && item == null){item = other.gameObject;isBack = true;item.transform.parent = transform;item.transform.position = transform.TransformPoint(Vector3.zero); // 将局部原点转换为世界坐标并设置位置item.transform.rotation = transform.rotation; // 将旋转角度设置为当前对象的旋转角度}
}

效果
在这里插入图片描述

随机生成物品

新增ItemSpawner,定义在spawnAreaSize区域内随机生成itemPrefabs物品

public class ItemSpawner : MonoBehaviour
{public static ItemSpawner Instance;public GameObject[] itemPrefabs; // 物品预设private int itemCount; // 要生成的物品数量public GameObject spawnAreaSize; // 生成区域大小的 GameObjectprivate List<Vector3> spawnedPositions = new List<Vector3>(); // 已生成物品的位置列表private void Awake() {Instance = this;}void Start(){SpawnItems();}public void SpawnItems(){// 循环遍历子物体for (int i = transform.childCount - 1; i >= 0; i--){// 获取当前子物体Transform child = transform.GetChild(i);// 销毁子物体Destroy(child.gameObject);}itemCount = Random.Range(5, 10);for (int i = 0; i < itemCount; i++){Vector3 randomPosition = GetRandomPosition();GameObject itemPrefab = itemPrefabs[Random.Range(0, itemPrefabs.Length)];GameObject newItem = Instantiate(itemPrefab, randomPosition, Quaternion.identity);newItem.transform.parent = transform;spawnedPositions.Add(randomPosition);}}Vector3 GetRandomPosition(){Vector3 spawnSize = spawnAreaSize.transform.localScale;Vector3 randomPosition = new Vector3(Random.Range(spawnAreaSize.transform.position.x - spawnSize.x / 2, spawnAreaSize.transform.position.x + spawnSize.x / 2),Random.Range(spawnAreaSize.transform.position.y - spawnSize.y / 2, spawnAreaSize.transform.position.y + spawnSize.y / 2),Random.Range(spawnAreaSize.transform.position.z - spawnSize.z / 2, spawnAreaSize.transform.position.z + spawnSize.z / 2));// 检查生成的位置是否与已有的物品位置重叠while (CheckOverlap(randomPosition)){randomPosition = new Vector3(Random.Range(spawnAreaSize.transform.position.x - spawnSize.x / 2, spawnAreaSize.transform.position.x + spawnSize.x / 2),Random.Range(spawnAreaSize.transform.position.y - spawnSize.y / 2, spawnAreaSize.transform.position.y + spawnSize.y / 2),Random.Range(spawnAreaSize.transform.position.z - spawnSize.z / 2, spawnAreaSize.transform.position.z + spawnSize.z / 2));}return randomPosition;}bool CheckOverlap(Vector3 position){foreach (Vector3 spawnedPos in spawnedPositions){if (Vector3.Distance(position, spawnedPos) < 1.0f ) // 这里的1.0f是一个简单的重叠检测距离阈值{return true;}}return false;}
}

效果,每次加载都会生成不同的物品
在这里插入图片描述
在这里插入图片描述

其他

一些基本的UI,场景切换,音乐音效等等这里就不多介绍了。当然过程出现任何问题或者有更好的方法,也欢迎留下你的评论一起探讨。

源码

整理好了我会放上来的

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,以便我第一时间收到反馈,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇,https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,出于兴趣爱好,最近开始自学unity,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!php是工作,unity是生活!如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~

在这里插入图片描述

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

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

相关文章

数据管理.

1 概述 在移动互联网蓬勃发展的今天,移动应用给我们生活带来了极大的便利,这些便利的本质在于数据的互联互通。因此在应用的开发中数据存储占据了非常重要的位置,HarmonyOS应用开发也不例外。 本文将为您介绍HarmonyOS提供的数据管理能力之一首选项。 2 什么是首选项 首选…

剧本杀小程序开发:数字化发展下的行业优势

跟着好友一起约着去玩剧本杀&#xff0c;这已经成为了年轻人社交休闲的新方式。如今&#xff0c;数字化的应用为剧本杀行业带来了全新的生命力。剧本杀开始向线上发展&#xff0c;利用各种技术&#xff0c;让玩家在手机上体验到虚拟游戏带来的乐趣。 线上剧本杀摆脱了时间空间…

【动态规划七】背包问题

目录 0/1背包问题 一、【模板】01背包 二、分割等和子集 三、目标和 四、最后一块石头的重量 II 完全背包问题 一、【模板】完全背包 二、零钱兑换 三、零钱兑换 II 四、完全平方数 二维费用的背包问题 一、一和零 二、盈利计划 似包非包 组合总和 卡特兰数 不…

AI大模型应用开发实践:4.基于 Chat Completions API 实现外部函数调用

基于 Chat Completions API 实现外部函数调用 2023年6月20日,OpenAI 官方在 Chat Completions API 原有的三种不同角色设定(System, Assistant, User)基础上,新增了 Function Calling 功能。 详见OpenAI Blog functions 是 Chat Completion API 中的可选参数,用于提供…

matlab使用教程(80)—修改图形对象的透明度

1.更改图像、填充或曲面的透明度 此示例说明如何修改图像、填充或曲面的透明度。 1.1坐标区框中所有对象的透明度 透明度值称为 alpha 值。使用 alpha 函数设置当前坐标区范围内所有图像、填充或曲面对象的透明度。指定一个介于 0&#xff08;完全透明&#xff09;和 1&#x…

15.回归问题

回归问题是机器学习领域中的核心问题之一&#xff0c;它旨在通过拟合数据点来建立数学模型&#xff0c;以预测因变量的值。回归问题不仅广泛应用于金融、医疗、工程等领域&#xff0c;也是数据分析和机器学习算法研究的重要基础。本文将深入探讨回归问题的基本概念、数学原理、…

软件设计师-上午题-计算题汇总

一、存储系统 - 存储容量计算&#xff08;字节编址、位编址、芯片个数&#xff09; 内存地址是16进制 内存地址编址的单位是Byte&#xff0c;1K1024B 1B 8 bit 1.计算存储单元个数 存储单元个数 末地址 - 首地址 1 eg. 按字节编址&#xff0c;地址从 A4000H 到 CBFFFH&…

ubuntu20.04 10分钟搭建无延迟大疆无人机多线程流媒体服务器

1.使用效果 无人机画面 2.服务器视频端口 3.使用教程 3.1.下载ubuntu对应软件包&#xff1a;系统要求ubuntu16以上 3.2修改端口&#xff08;config.xml文件&#xff09; 3.3启动服务 目录下输入&#xff1a;终端启动&#xff1a;./smart_rtmpd 后台启动&#xff1a;nohup ./…

安卓手机APP开发__平台的架构

安卓手机APP开发__平台的架构 目录 概述 安卓软件栈 Linux内核 硬件抽象层(HAL) 安卓运行时 原生的C/C代码库 Java API框架 系统APP 概述 安卓是一个开源的&#xff0c;基于Linux的软件栈&#xff0c;它创建一个设备和形式因素的很宽的矩阵。 下图展示了安卓平台的所有…

Kubernetes的灵魂核心:kube-scheduler

Kubernetes&#xff08;简称K8s&#xff09;是一个开源的容器编排系统&#xff0c;用于自动化容器化应用程序的部署、扩展和管理。在Kubernetes集群中&#xff0c;kube-scheduler是一个至关重要的组件&#xff0c;它负责将Pod&#xff08;Kubernetes中的最小部署单元&#xff0…

2024年电工杯高校数学建模竞赛(A题) 建模解析| 园区微电网风光储协调优化配置 |小鹿学长带队指引全代码文章与思路

我是鹿鹿学长&#xff0c;就读于上海交通大学&#xff0c;截至目前已经帮200人完成了建模与思路的构建的处理了&#xff5e; 本篇文章是鹿鹿学长经过深度思考&#xff0c;独辟蹊径&#xff0c;实现综合建模。独创复杂系统视角&#xff0c;帮助你解决电工杯的难关呀。 完整内容可…

Anti Desgin Vue 实现 表格可编辑、新增、删除功能

1、效果图 新增&#xff1a; 删除&#xff1a; 修改&#xff1a; 代码&#xff1a; <template><div><button click"add">添加</button><span style"margin-left: 8px"><template v-if"hasSelected">{…

C++语言基础光速入门笔记

目录 从C到CC和C语言的关系C编译器C面向对象程序设计标准库ANSI 标准C的使用场景标准化 安装 GNU 的 C/C 编译器g 应用说明g 常用命令选项 C 基本语法C 关键字三字符组 C 数据类型基本的内置类型typedef 声明枚举类型类型转换静态转换&#xff08;Static Cast&#xff09;动态转…

沃通国密根证书入根红莲花浏览器,共建国密HTTPS应用生态

近日&#xff0c;沃通CA与海泰方圆红莲花安全浏览器进一步达成合作&#xff0c;沃通新增国密根证书入根红莲花安全浏览器。此次入根合作&#xff0c;标志着沃通国密数字证书产品兼容性再次得到提升&#xff0c;进一步夯实国密应用根基。 沃通CA入根红莲花浏览器&#xff0c;自动…

手机端如何访问本地vue+vite项目,实现实时调试?

一、应用场景 h5&#xff08;vuevite&#xff09;嵌入app后&#xff0c;出现某种问题时&#xff0c;需要每次发布坏境后&#xff0c;才能才看效果&#xff0c;这种来回很耗时间&#xff0c;本文章在于解决手机端直接访问本地启动应用项目&#xff0c;无需重复发布坏境 二、实…

四川易点慧电商抖音小店未来商业新蓝海

在数字经济的浪潮中&#xff0c;电商行业日新月异&#xff0c;不断涌现出新的商业模式和平台。四川易点慧电商抖音小店作为其中的佼佼者&#xff0c;以其独特的商业模式和广阔的市场前景&#xff0c;正成为越来越多创业者和商家的首选。本文将从多个角度探讨四川易点慧电商抖音…

docker 指定jdk11镜像执行jar

dockerfile :下载jdk11 并将上传的jar 放入jdk11容器/root&#xff0c;改名为app.jar vi dockerfile 。。。。内容见下图 # 构建jdk11镜像 docker build -t demo . # 也可以通过jdk11镜像&#xff08;前提有jdk11镜像&#xff09;外挂载目录方式运行jar docker run --name d…

惠普电脑怎么进入bios?图文教程助你轻松上手!

进入BIOS&#xff08;基本输入/输出系统&#xff09;是在电脑启动时进行硬件初始化和设置的重要步骤之一。对于惠普&#xff08;HP&#xff09;电脑用户来说&#xff0c;了解如何进入BIOS是解决一些硬件和系统问题的关键。本文将介绍惠普电脑怎么进入bios的三种方法&#xff0c…

java学习和项目总结

java&#xff1a; JDK/JRE/JVM三者的关系 JVM&#xff1a;JVM是java进行编译的虚拟机&#xff0c;是Java 能够跨平台运行的核心 。 所有的java程序会首先被编译为.class的类文件&#xff0c;这种类文件可以在虚拟机上执行。也就是说class文件并不直接与机器的操作系统交互&a…

Day24:Leetcode:235. 二叉搜索树的最近公共祖先 + 701.二叉搜索树中的插入操作 + 450.删除二叉搜索树中的节点

LeetCode&#xff1a;235. 二叉搜索树的最近公共祖先 解决方案&#xff1a; 1.思路 对于当前节点x&#xff0c;如果x比p和q的值都大&#xff0c;说明&#xff0c;p和q在x的右子树里面&#xff0c;那么去x的右子树里面去寻找&#xff1b;对于当前节点x&#xff0c;如果x比p和…