Unity小游戏——迷你拼图

这篇具有很好参考价值的文章主要介绍了Unity小游戏——迷你拼图。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

 游戏展示

拼图演示

资源: 

链接:https://pan.baidu.com/s/1BGeSmRCO_WZRUyl3MxefGw 
提取码:0n4a


一、玩法介绍

排列拼图碎片,拼出最后的图案。可以点住碎片的任意位置拖动;点击"重来"按钮,可以回到最初状态重新开始。

二、流畅的拖拽操作

有很多电脑游戏的原型来自于现实世界中的玩具,拼图游戏就是其中的一个代表。

本文我们介绍的拼图游戏虽然是一款玩法比较简单的游戏,不过这并不意味着开发也非常简单。

相对于其他游戏通过操作键盘或移动鼠标来控制角色的运动方向,拼图游戏通过鼠标的拖拽直接移动拼图的碎片。

游戏的核心在于流畅的拖拽操作

除了拖拽操作外,我们也可以借此机会思考一下诸如"当碎片移动到正确的位置附近时会被吸附到正确的位置"等触屏游戏的小细节。

三、点住碎片的任意位置拖动

Unity可以很容易判断出"某个对象受到了点击",不过如果要实现自然流畅的操作,我们仍需下功夫。这里,为了让鼠标的拖拽操作更急接近"用手指摁住移动"的效果,我们需要考虑一下如何才能点住碎片的任意位置拖动。

1、透视变换和逆透视变换

鼠标的光标位于屏幕上时,其位置坐标位于二维坐标系内。而拼图碎片位于3D空间内,所以其位置坐标自然有三个维度。为了比较鼠标光标和拼图碎片的位置,必须将它们放入相同的坐标系。因此,我们使用逆透视变换的方法,将鼠标光标的坐标变换至三维坐标系

2、被点击处即为光标的位置

通过逆透视变换将鼠标光标和拼图碎片的坐标统一到相同的坐标系后,我们就该尝试通过拖拽使拼图移动了,只需要在点击按键的瞬间,将鼠标光标的坐标复制到拼图碎片的坐标即可。这种方法确实非常简单,不过它有个缺点:鼠标光标总是显示在拼图碎片的中心。

在本游戏中,拼图碎片被点击的位置并不影响游戏的玩法。不过,对于某些游戏而言,点击位置的不同可能会改变角色的朝向,或者是游戏角色以光标为中心摆动,这些情况下在何处点击就变得很重要了。

而且,即使不影响游戏的核心玩法,点击的瞬间拼图碎片会突然移动一下这种体验也很糟糕。尽管有些时候这种机制可能会更好,但是为了应对不同的要求,我们还是需要掌握如何能点住碎片的任意处拖动。

在本游戏中,碎片的点击判断都是通过Unity的网格碰撞器实现的。网格碰撞器采用网格进行碰撞检测,点击拼图碎片的任何部位都将发生碰撞。对于玩家来说点击碎片的哪个位置都可以,这反映到程序中就是"不用关心碎片的何处受到了点击"。

点击的瞬间,鼠标光标不一定位于碎片的中心。两者的坐标存在一定的差距,我们将这种坐标的差距称为偏移

之前我们把光标的坐标原原本本地复制到碎片坐标时,因为两个坐标值相同所以差距为0,这种坐标差的急剧变化正是导致拼图碎片突然移动的原因。

知道了坐标偏移值的变化是问题所在后,我们来考虑如何固定这个偏移值。首先,要在鼠标点击拼图碎片的瞬间,也就是开始拖动的时候,计算出鼠标光标和碎片中心的坐标差,得到的值就是偏移值。

偏移=碎片的位置-鼠标光标的位置

拖动的过程中则与之相反,用鼠标光标的位置加上偏移值就可以得到碎片的位置

碎片的位置=鼠标光标位置+偏移值

这样一来,鼠标光标距离碎片中心总是保持一定的距离,这样就保证了鼠标点击瞬间的位置就是碎片被拖拽的位置。

下面来看看实际的代码

private void begin_dragging()
	{
		do {

			// 将光标坐标变换为3D空间内的世界坐标

			Vector3 world_position;
	
			if(!this.unproject_mouse_position(out world_position, Input.mousePosition)) {

				break;
			}

			if(PieceControl.IS_ENABLE_GRAB_OFFSET) {

				// 求出偏移值(点击位置距离碎片的中心有多远)
				this.grab_offset = this.transform.position - world_position;
			}

		} while(false);
	}
private void do_dragging()
	{
		do {

			// 将光标坐标变换为3D空间内的世界坐标
			Vector3 world_position;

			if(!this.unproject_mouse_position(out world_position, Input.mousePosition)) {

				break;
			}

			// 加上光标坐标(3D)的偏移值,计算出碎片的中心坐标
			this.transform.position = world_position + this.grab_offset;

		} while(false);
	}

四、打乱拼图碎片

商店里售卖纸质拼图游戏时一般会将拼图碎片打乱顺序后放入包装盒中。虽然也有些是已经拼好的状态,不过玩家在开始游戏之前还是要将各碎片的顺序打乱。

有很多事情都是"人类做起来很简单,计算机处理起来却很难",比如将拼图碎片全部打乱这件事就是一个例子。

Unity提供了取得随机数的方法,不过单纯使用该方法似乎并不能达到打乱碎片顺序的目的。

这里我们不妨来分析一下如何随机打乱各拼图碎片的顺序。

1、设置拼图碎片的坐标为随机数

最简单的随机打乱拼图碎片的方法是,直接将随机数代入各个碎片的坐标。只要控制好随机数的范围,就能让各个拼图碎片随机分布在画面上。

但这种方式的弊端也很明显,就是有很多拼图碎片可能叠在一起。虽然这样也未尝不可,不过可以的话最好还是将各碎片均匀分散开。如果很多碎片重叠在一起,就可能导致下面的碎片被覆盖而无法看见。

2、改进策略

首先我们整理一下拼图碎片随机散开的要求,即需求分析

  • 碎片之间彼此互不重叠
  • 碎片散开分布到整个画面上
  • 随机分散各个碎片

需求基本上就是这样。如果拼图碎片的数量有所增加,可能还需要追加一项"能够控制游戏的难易度"。

接下来我们对实现方法进行说明。首先简单熟悉一下整体流程

  1. 将拼图碎片分配到网格中
  2. 打乱拼图碎片的排列顺序
  3. 在网格内通过随机坐标调整碎片的位置
  4. 将整个拼图随机旋转一定角度

我们可以选择任意图片,将其分割成几块。这里我们选择一个"猫头鹰"图片,将其分割成8块。

首先,将所有的拼图碎片从左上角开始依次放入网格中。

该网格的行数和列数相同,并且网格总数达于拼图碎片数量。"猫头鹰"拼图碎片数量为8,我们就搞一个3✖️3的网格,空出来的格子不用理会。根据碎片数量的不同,有时候剩余的格子会比较多,这种情况下可以调整网格的行数和列数。

所有网格块都为正方形,且都应当能确保能够容纳下拼图碎片。另外,因为后续步骤在网格内移动拼图碎片,所以还需要在确保整体网格不溢出画面的前提下适当放大网格的尺寸。

之所以想这样把拼图碎片纺织到网格中,是为了避免出现碎片之间彼此重叠的状况。

接下来随机打乱个碎片的排列位置

在第一个步骤中,我们将碎片从左上角开始依次放入了网格中。而第二个步骤就是打乱各个碎片的排列顺序。利用随机数选出两个网格,案后交换其中的碎片空白的网格也可以参与交换。

做到这里,前面我们做出的需求分析中,"碎片之间彼此互不重叠","碎片分散于整个画面"和"随机分散各个碎片"就已经基本得到了实现。不过从程序实际情况来看,很容易发现拼图碎片被规则地排列在了网格上。我们得想办法让这种随机分散的效果更真实。

在第三个步骤中,我们让拼图碎片在网格中随机移动。

最初的步骤中增加网格尺寸的用意就在于为这里的碎片移动做准备。如果网格的尺寸太小,将无法移动碎片,反之如果太大,则会令碎片之间过于松散。我们需要结合拼图碎片的大小和画面整体的尺寸,调整网格尺寸为最佳值,

最后,为了不让玩家看出碎片排列的规律性,稍微将拼图网格整体旋转一定的角度

虽然旋转了整体的网格,但是需要保持拼图碎片自身的角度不变。

下面,我们结合实际代码来看看这一流程文章来源地址https://www.toymoban.com/news/detail-634677.html

private void	shuffle_pieces()
	{
	#if true
		// 将碎片按照网格顺序排列

		int[]		piece_index = new int[this.shuffle_grid_num*this.shuffle_grid_num];

		for(int i = 0;i < piece_index.Length;i++) {

			if(i < this.all_pieces.Length) {

				piece_index[i] = i;

			} else {

				piece_index[i] = -1;
			}
		}

		// 随机选取两个碎片,交换位置

		for(int i = 0;i < piece_index.Length - 1;i++) {

			int	j = Random.Range(i + 1, piece_index.Length);

			int	temp = piece_index[j];

			piece_index[j] = piece_index[i];

			piece_index[i] = temp;
		}
	
		// 通过位置的索引变换为实际的坐标来进行配置

		Vector3	pitch;

		pitch = this.shuffle_zone.size/(float)this.shuffle_grid_num;

		for(int i = 0;i < piece_index.Length;i++) {

			if(piece_index[i] < 0) {

				continue;
			}

			PieceControl	piece = this.all_pieces[piece_index[i]];

			Vector3	position = piece.finished_position;

			int		ix = i%this.shuffle_grid_num;
			int		iz = i/this.shuffle_grid_num;

			position.x = ix*pitch.x;
			position.z = iz*pitch.z;

			position.x += this.shuffle_zone.center.x - pitch.x*(this.shuffle_grid_num/2.0f - 0.5f);
			position.z += this.shuffle_zone.center.z - pitch.z*(this.shuffle_grid_num/2.0f - 0.5f);

			position.y = piece.finished_position.y;

			piece.start_position = position;
		}

		// 逐步(网格的格子内)随机移动位置

		Vector3		offset_cycle = pitch/2.0f;
		Vector3		offset_add   = pitch/5.0f;

		Vector3		offset = Vector3.zero;

		for(int i = 0;i < piece_index.Length;i++) {

			if(piece_index[i] < 0) {

				continue;
			}

			PieceControl	piece = this.all_pieces[piece_index[i]];

			Vector3	position = piece.start_position;

			position.x += offset.x;
			position.z += offset.z;

			piece.start_position = position;

			//


			offset.x += offset_add.x;

			if(offset.x > offset_cycle.x/2.0f) {

				offset.x -= offset_cycle.x;
			}

			offset.z += offset_add.z;

			if(offset.z > offset_cycle.z/2.0f) {

				offset.z -= offset_cycle.z;
			}
		}

		// 使全体旋转

		foreach(PieceControl piece in this.all_pieces) {

			Vector3		position = piece.start_position;

			position -= this.shuffle_zone.center;

			position = Quaternion.AngleAxis(this.pazzle_rotation, Vector3.up)*position;

			position += this.shuffle_zone.center;

			piece.start_position = position;
		}

		this.pazzle_rotation += 90;

	#else
		// 简单地使用随机数来决定坐标时的情况
		foreach(PieceControl piece in this.all_pieces) {

			Vector3	position;

			Bounds	piece_bounds = piece.GetBounds(Vector3.zero);

			position.x = Random.Range(this.shuffle_zone.min.x - piece_bounds.min.x, this.shuffle_zone.max.x - piece_bounds.max.x);
			position.z = Random.Range(this.shuffle_zone.min.z - piece_bounds.min.z, this.shuffle_zone.max.z - piece_bounds.max.z);

			position.y = piece.finished_position.y;

			piece.start_position = position;
		}
	#endif
	}

到了这里,关于Unity小游戏——迷你拼图的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 拼图小游戏(实现游戏主界面)(未连接数据库)

    基于IDEA,创建窗体进行游戏 默认的用户名和密码为:zhangsan,123                                         lisi,1234

    2024年01月16日
    浏览(47)
  • 使用wxPython和pillow开发拼图小游戏(四)

           上一篇介绍了使用本地图片来初始化游戏的方法,通过前边三篇,该小游戏的主要内容差不多介绍完了,最后这一篇来介绍下游戏用时的计算、重置游戏和关闭窗口事件处理 游戏用时的计算        对于游戏用时的记录,看过前几篇的小伙伴可能也发现了,这里主要

    2024年02月16日
    浏览(34)
  • 使用wxPython和pillow开发拼图小游戏(一)

    刚学习python,心血来潮,使用wxPython和pillow开了一个简单的拼图小游戏,大家分享一下 wxPython是Python语言的一套优秀的GUI图形库,在此项目里主要用来开发GUI客户页面;Pillow是一个非常好用的图像处理库,在此项目中主要用来对图片进行填充、切割、保存等操作。 项目初始化

    2024年02月16日
    浏览(39)
  • Unity - 微信小游戏

    总参考:Unity WebGL 微信小游戏适配方案(公测)   下载 Unity插件,并导入至游戏项目中,版本更新请查看更新日志 请查阅推荐引擎版本,安装时选择 WebGL 组件 最终选择 Unity2021.2.5f1c1 InstantGame 前往Node官网安装长期稳定版 之前已安装 v16.17.0 前往微信开发者工具下载安装 Stable

    2024年02月06日
    浏览(54)
  • Java拼图小游戏------《Java程序设计》课程设计

    目录 1.1 研究的背景  1.2 研究的意义  1.3 国内外研究现状  国内研究现状: 国外研究现状:          2.1 Java技术          2.2 GUI技术           2.3 内容设计要求及算法的实现 内容: 要求: 设计算法实现:          3.1设计流程图          3.2系统界面展示          

    2024年02月04日
    浏览(43)
  • unity小球吃金币小游戏

    链接放在这里 unity小球吃金币小游戏-Unity3D文档类资源-CSDN下载 这是我在学完虚拟现实技术这门课程后利用unity所做的小球吃金币小游戏,里面有源码和作品源文件,用u更多下载资源、学习资料请访问CSDN下载频道. https://download.csdn.net/download/m0_57324918/85604051 1创建Roll A Ball小球吃

    2023年04月08日
    浏览(45)
  • 【Unity】小球吃方砖小游戏

    目录 游戏背景 游戏开发         2.1场景布置         2.2小球运动         2.3镜头跟踪         2.4吃掉方砖         2.5结束提示 游戏录制           用wasd(↑←↓→)操控小球进行平面滑动,小球触碰会原地打转的立方体后立方体会消失,消除5个小球后提示

    2024年02月09日
    浏览(37)
  • Unity 开发微信小游戏

    今天给大家分享一下我近期用Unity开发微信小游戏的经过和踩坑; 微信小游戏就是微信小程序,小游戏是小程序的一个子集,小游戏是一种特殊的小程序;这篇文章建议大家收藏,干货满满 Unity开发微信小程序 Unity 3D下载官网 Unity转化小程序的Package包下载地址 微信开发者工

    2024年02月09日
    浏览(40)
  • Unity——2D小游戏笔记整理

    【每日一句:清晨和夜晚都请用尽全力去生活】 目录 一、环境搭建 二、人物 三、相机跟随人物移动 四、平铺精灵 五、血条跟随敌人行走 六、脚本逻辑 【玩家行走方法】 【玩家跳跃方法】 【改变玩家血量值方法】 【创建玩家子弹方法】 【主角血量,改变血条遮罩】 【敌

    2024年02月09日
    浏览(52)
  • 【Unity小游戏】《捕鱼达人》小游戏来啦~ 有源码下载【文末送书】

    📢博客主页:https://blog.csdn.net/zhangay1998 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! 📢本文由 呆呆敲代码的小Y 原创,首发于 CSDN 🙉 📢未来很长,值得我们全力奔赴更美好的生活✨

    2023年04月08日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包