本文是Unity3D贪吃蛇游戏从制作到部署的相关细节 项目开源代码:https://github.com/zstar1003/3D_Snake 试玩链接:http://xdxsb.top/Snake_Game_3D 效果预览: 试玩链接中的内容会和该效果图略有不同,后面会详细说明。

游戏规则

经典贪吃蛇游戏:蛇身随着吃食物的增加不断变长,通过A/D或方向键←→控制方向,蛇头撞在蛇身上或四周墙壁会导致游戏失败。

蛇身控制和碰撞检测

蛇身控制和碰撞检测的逻辑写在SnakeController.cs文件中。

蛇头运动的思路是将蛇头不断朝forward的方向前进,前进速度等于速度数值x当前时间。同时通过一个list来记录蛇头运动的历史轨迹,蛇身通过该轨迹进行运动。

为了区分延申出来的蛇身是初始蛇身还是新延申的蛇身,对新延申的蛇身打上Block标签,不进行区分则会导致刚开始碰撞即触发蛇头蛇身碰撞,导致游戏结束。

完整代码:

using System;

using System.Collections;

using System.Collections.Generic;

using System.Linq;

using UnityEngine;

using UnityEngine.SceneManagement;

public class SnakeController : MonoBehaviour

{

// 设置

public float moveSpeed = 5f;

public float steerSpeed = 180f;

public float bodySpeed = 5f;

public int Gap = 10;

// 预制体

public GameObject bodyPrefab; //身体组件

// 身体组件集合

private List _bodyParts = new List();

private List _positionHistory = new List();

//音乐控制器

public AudioController audioController;

private void Start()

{

addBodyPart();

audioController = GameObject.FindGameObjectWithTag("Audio").GetComponent();

}

private void Update()

{

// 向前移动

transform.position += transform.forward * moveSpeed * Time.deltaTime;

// 方向操控

float steerDirection = Input.GetAxis("Horizontal"); // 返回值从 -1 到 1

transform.Rotate(Vector3.up * steerDirection * steerSpeed * Time.deltaTime);

// 保存位置移动史

_positionHistory.Insert(0, transform.position);

// 移动身体组件

int index = 0;

foreach (var body in _bodyParts)

{

Vector3 point = _positionHistory[Mathf.Clamp(index * Gap, 0, _positionHistory.Count - 1)];

// 让贪吃蛇的身体组件沿着头部的移动轨迹运动

Vector3 moveDirection = point - body.transform.position;

body.transform.position += moveDirection * bodySpeed * Time.deltaTime;

// 让身体组件朝向头部移动的方向

body.transform.LookAt(point);

index++;

}

}

// 蛇身延长

private void addBodyPart()

{

GameObject body = Instantiate(bodyPrefab, new Vector3(0, transform.position.y, 0), Quaternion.identity);

_bodyParts.Add(body);

}

// 后续添加的body打上Block标签

private void addBodyPart_Block()

{

GameObject body = Instantiate(bodyPrefab, new Vector3(0, _bodyParts.Last().transform.position.y, 0), Quaternion.identity);

body.tag = "Block";

_bodyParts.Add(body);

}

//触发检测

private void OnTriggerEnter(Collider other)

{

if (other.tag == "Food")

{

//必须先删除,否则会导致多次触发

Destroy(other.gameObject);

addBodyPart_Block();

GameObject.Find("SpawnPoint").GetComponent().SpawnItems();

audioController.PlaySfx(audioController.eat);

}

else if (other.tag == "Block")

{

SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);

}

}

}

食物旋转

控制食物旋转比较简单,在update中加入Rotate即可。

Food.cs

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class Food : MonoBehaviour

{

void Start()

{

}

void Update()

{

//旋转

transform.Rotate(Vector3.up);

}

}

食物随机生成

食物随机生成我并没有采用随机数的方式,三维场景容易出现问题。因此这里在场景中添加了6个食物生成的点位,当食物被触发之后,在随机的一个点位上生成新的食物。

SpawnItem.cs

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class SpawnItem : MonoBehaviour

{

public Transform[] SpawnPoints;

public float spawnTime = 2.5f;

public GameObject Items;

void Start()

{

}

void Update()

{

}

public void SpawnItems()

{

int spawnIndex = Random.Range(0, SpawnPoints.Length);

Instantiate(Items, SpawnPoints[spawnIndex].position, SpawnPoints[spawnIndex].rotation);

}

}

场景切换

这里对于游戏开始界面和结束界面分别用不同的场景进行隔离,切换时只需一行代码:

SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);

这里的Index为打包时场景的序号顺序。

本地WebGL测试

使用WebGL打包之后,会得到3个文件夹和一个index.html文件,直接打开index.html会报错,需要使用服务器方式去运行。

首先在win10上配置服务器相关组件,参考之前的博文【实用技巧】Win10搭建局域网FTP服务器。

之后在打包的文件夹下新建一个文件web.config,输入以下内容:

之后在iis中,新建一个http服务器,选择一个不被占用的端口,我这里选择8080端口。

开启网站后,在浏览器输入http://localhost:8080/,即可访问测试。

Github部署

Github部署非常容易,新建一个仓库,将打包出的内容直接上传。

然后在Settings/Pages选择main分支,点击Save,过几分钟就会在上方出现访问网址。

遗留问题:打包前后测试不一致

目前该项目在untiy运行测试时正常, 但打包出webgl或exe时,却出现蛇身分离的情况,看了一些打包时的选项,仍未解决该问题,有了解这一问题的读者欢迎在评论区交流。

推荐阅读

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。