经典小游戏开发思路和算法之拼图(1)
此次开发小游戏一共有18个经典小游戏,每天更新一个。跟大家一起学习一些经典小游戏的开发思路和算法,如果想直接看完整游戏效果的,相关的完整工程可以直接去我的资源里面下载。与大家一起学习One day.
今天这个是拼图小游戏
简单说一下拼图游戏:
拼图游戏是一款经典的益智类游戏,它的历史可以追溯到1760年左右,是英国的雕刻师和制图师把地图贴在硬纸板上,然后沿着国界线分割,制作成了最原始的拼图。最初的拼图游戏具有教育意义,拼图所用的图片多向人们传授历史或地理知识,后来五花八门的拼图游戏层出,不过大多都是有益于人们脑力的开发和训练记忆力提高动手能力的。
游戏规则:
将一张图片分成若干份(碎片),玩家将这些碎片按照原来的样式拼接起来,则视为游戏成功。
下面我们来说一下开发思路:
1.游戏流程图:
2.原图与碎片一一对应坐标
用33九宫格来设计此款拼图游戏,可以将构成原图的9个碎片用不同的整数来表示(如,1,2,3,4,5,6,7,8,9),并保存到一个33的二维数组中。
如果碎片的宽为w,高为h,碎片的中心位置即为碎片的坐标位置,二维数组的第一个元素图片位于原图的左下角。
当原图的左下角坐标为世界坐标的原点坐标,即(0,0)位置,假设当前图片在二维数组索引号为[i][j],那么当前碎片的具体位置公式如下:(x=(i+1/2)*w,y=(j+1/2)*h)
3.相应的互动操作
鼠标拖拽移动碎片的功能:
(1).判断鼠标的点击位置是否在碎片内 (例如碎片左下角的坐标为(sx,sy))即在碎片的内部坐标范围sx<x<sx+w,sy<y<sy+h. 若鼠标的世界坐标的位置在此范围内,则可以判断碎片被选中。
注:鼠标的屏幕坐标一定要转换为世界坐标。
(2).实现被拖拽的碎片跟随鼠标移动:
把鼠标的屏幕坐标转换为世界坐标,然后计算鼠标位置和碎片位置的偏移值,公式如下:
碎片坐标=鼠标的世界坐标+碎片位置和鼠标位置的偏移量。
(3).鼠标松开时:
获得碎片的当前位置,如果靠近对应的正确位置坐标(设置一个距离的临界值,如果对应正确位置和碎片位置之间小于这个临界值)则将碎片放到正确位置,否则就放回碎片池里。
4.正确判断
碎片位置和对应正确位置的距离计算:
假设A(x1,y1)和B(x2,y2)分别对应碎片的位置和对应的正确位置,我们可以通过一下公式计算
|AB|²=(x1-x2)²+(y1-y2)² 原式是要开根号的,但是开根号比较消耗计算资源,所以我们可以直接用这个式子。
也可以直接用两个坐标点的位置进行判断,如获取的碎片的坐标(sx,sy),对应的正确的位置(Tx,Ty)
伪代码如下:
if(|Tx-Sx|<临界值&&|Ty-Sy|<临界值)
{
碎片坐标=正确坐标;
}
else
{
碎片回到原来位置;
}
5.获胜判断
当所有碎片都放到对应的正确位置就为获胜,我们设置一个变量用来计数,每当一个碎片被放置到正确位置之后,该变量就+1,当这个变量等于碎片的总数时,就说明所有的碎片都被放置到了正确的位置。这时判定获胜游戏结束;可以设置超时,超时则游戏失败!
(如果你看到了这篇博客不妨在看下面的游戏实现之前自己先去写写)
下面是游戏实现:
具体的实现代码如下:
CreatePic类加载资源,初始化界面
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CreatePic : MonoBehaviour {
public string sprit_Path = "Sprites/Pictures";
public Sprite[] sp_S;//所有的图片
public int textureNum = -1;//图片序号
public static GameObject[,] pic = new GameObject[3,3];
public static bool isSetTruePosition = false;
/// <summary>
/// 加载资源,并初始化界面
/// </summary>
void Start () {
sp_S = Resources.LoadAll<Sprite>(sprit_Path);
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
textureNum++;
pic[i,j] = new GameObject("picture" + i + j);
//给物体一个贴图
pic[i,j].AddComponent<SpriteRenderer>().sprite = sp_S[textureNum];
//将碎片放置到随机的位置
pic[i,j].GetComponent<Transform>().position = new Vector2(Random.Range(3.0f,5.5f),Random.Range(0.0f,2.5f));
}
}
}
}
MouseDrag 类鼠标的拖拽操作的代码实现:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MouseDrag : MonoBehaviour
{
private Vector2 _vec3Offset; // 偏移
public Vector2 _ini_pos; //初始位置
private Transform targetTransform; //目标物体
public static int width = 3;
public static int height = 3;
public float threshold = 0.2f; //临界值
private bool isMouseDown = false; //鼠标是按下
private Vector3 lastMousePosition = Vector3.zero;
float chipWidth = 1; //碎片宽度
float chipHeight = 1; //碎片高度
void Update()
{
if (Input.GetMouseButtonDown(0))
{
isMouseDown = true;
for(int i = 0;i<width;i++)
{
for(int j = 0;j<height;j++)
{
if(Mathf.Abs(Camera.main.ScreenToWorldPoint(Input.mousePosition).x - Done_CreatePic.pic[i, j].transform.position.x) <chipWidth/2
&& Mathf.Abs(Camera.main.ScreenToWorldPoint(Input.mousePosition).y - Done_CreatePic.pic[i, j].transform.position.y) < chipHeight/2)
{
targetTransform = Done_CreatePic.pic[i, j].transform;
_ini_pos = new Vector2(targetTransform.position.x, targetTransform.position.y);//记录碎片初始位置
break;
}
}
}
}
if (Input.GetMouseButtonUp(0))
{
isMouseDown = false;
lastMousePosition = Vector3.zero;
OnMyMouseUp();
}
if (isMouseDown)
{
if (lastMousePosition != Vector3.zero)
{
//将目标物体置于最上层
targetTransform.GetComponent<SpriteRenderer>().sortingOrder = 100;
Vector3 offset = Camera.main.ScreenToWorldPoint(Input.mousePosition) - lastMousePosition;//鼠标偏移量
//碎片当前位置 = 碎片上一帧的位置 + 鼠标偏移量
targetTransform.position += offset;
}
lastMousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
}
void OnMyMouseUp()
{
for(int j = 0;j<width;j++)
{
for(int i= 0;i<height;i++)
{
if(targetTransform.name == Done_CreatePic.pic[i,j].name)
{
if (Mathf.Abs(targetTransform.position.x - j) < threshold&& Mathf.Abs(targetTransform.position.y - i) < threshold)
{
Debug.Log("OnMyMouseUp");
targetTransform.position = new Vector2(j, i);
Done_GameOver._trueNum++;
Debug.Log(Done_GameOver._trueNum);
Done_GameOver.Judge();
break;
}
else
{
targetTransform.position = _ini_pos;
}
}
targetTransform.GetComponent<SpriteRenderer>().sortingOrder = 5;
}
}
}
}
GameOver 游戏结束判定
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameOver : MonoBehaviour {
public static int _trueNum;//到达正确位置的碎片的数量
private static int _allPicNum = 9;//碎片的数量
/// <summary>
/// 结束判定
/// </summary>
public static void Judge()
{
if (_trueNum == _allPicNum)
{
Debug.Log("游戏结束");
}
}
}
本文地址:https://blog.csdn.net/qq_42855293/article/details/85947708
上一篇: 数组与字符串——对角线遍历
下一篇: 从时代角度探究,3D建模师到底饱和了吗?