Unity做一个类似星露谷物语的游戏【5】

前言

hello and welcome back ,一个月不见 十分想念,最近外包狗有点忙,博客耽误了一下,以后一定一周一更~
今天我们来学习用tilemap创建场景,最基础的使用由于时间关系就先不赘述,今天讲的是使用tilemap
管理场景 ,比如哪些位置可以被锄头凿地,哪个地方可以放家具,哪个地方可以丢弃物品等

场景创建

简单介绍一下我的场景创建
右键->2D->tilemap->rectangular创建tilemap
Windows->2D->TilePalette打开画板

画板的使用

在这里插入图片描述
点击CreateNewPalette 把要切割的图片塞进去 就可以自动切割成小图片了,切成的类似于ui的sprite切割
切割之后我们就可以操作它在场景中随意涂画啦~

画图建议

笔者这里提一下我的场景布置 我这里将场景分了多个层
Ground1 用来画最基础的土地
Ground2 用来画场景中的花花草草,栏杆等物品
Ground3 用来画山,房子的前半面 原因下面讲
Instance 用来渲染玩家,植物,npc等物品
Front用来画房顶
Collision 用来画碰撞体

Ground3 画房子的前半面Front用来画房顶的原因:instance渲染要在Ground3后面,使用如果我不准备让玩家从红框位置穿过,如果可以穿过 给人的感觉就是爬着房子走过去,我又想让玩家在房顶位置穿过,因为front渲染在instance后面,玩家穿过不会被渲染出来,会给一种在房子后面穿过的感觉
当然 仁者见仁智者见智,大家不喜欢这个方法的话也可以按照自己的想法来搞,最重要的一点就是千万不要忘记创建新的Layer层,把Tilemap的SortLayer改成对应的渲染层
在这里插入图片描述

Tilemap的Collision

我们在collision层画好碰撞位置之后 我们要添加Rigidbody2D

创建格子信息

一个格子我们要知道它的x轴位置和y轴位置,这个格子的属性(是否可以被锄头锄,是否可以丢弃物品)
注意 格子信息之后要被存储 所以一定要把它序列化!!

格子位置信息

格子位置就是它的x轴和y轴的位置

[System.Serializable]
public class GridCoordinate
{
    public int x;
    public int y;
    public GridCoordinate(int x,int y)
    {
        this.x = x;
        this.y = y;
    }
    /// <summary>
    /// 显示转换
    /// </summary> 
    public static explicit operator Vector2(GridCoordinate grid)
    {
        return new Vector2((float)grid.x, (float)grid.y);
    }

    public static explicit operator Vector2Int(GridCoordinate grid)
    {
        return new Vector2Int(grid.x, grid.y);
    }
    public static explicit operator Vector3(GridCoordinate grid)
    {
        return new Vector3((float)grid.x, (float)grid.y,0);
    }

    public static explicit operator Vector3Int(GridCoordinate grid)
    {
        return new Vector3Int(grid.x, grid.y,0);
    }
}

格子的属性

格子的信息我现在只想到了是否可以锄地 是否可以丢弃物品,是否可以放置家具,是否可以让npc移动(A*那个模块我在来讲) 
这些信息我们可以用枚举来存储

public enum GridBoolProperty
{
    diggable,//是否可以被挖掘
    canDropItem,//是否可以被丢弃
    canPlaceFurniture, //是否可以放置家具
    isNPCObstacle//npc是否可以移动
}

格子的总信息

我们把前面两个信息整合到一起 就可以得到格子的总信息

[System.Serializable]
public class GridProperty 
{
    public GridCoordinate gridCoordinate;
    public GridBoolProperty gridBoolProperty;
    public bool gridBoolValue = false;

    public GridProperty(GridCoordinate gridCoordinate, GridBoolProperty gridBoolProperty, bool gridBoolValue)
    {
        this.gridCoordinate = gridCoordinate;
        this.gridBoolProperty = gridBoolProperty;
        this.gridBoolValue = gridBoolValue;
    }
}

格子的详细信息

详细信息我们要记录当前格子的详细信息,为了防止可以在种植过物品的位置重新种植物品,
目前包含的信息分别是格子在x轴的详细位置,格子在y轴的详细位置,是否被锄头砸过(砸过才可以种植种子),是否可以丢弃物品,是否可以放置家具,是否种植过物品(种植了物品就不能再次种植),是否交过水(不交水的话第二天种子不会成长),是否被砸过(砸过第二天没有种东西就会恢复成普通的地),种植的天数,距离上次收获的天数

public class GridPropertyDetails
{
    public int gridX;
    public int gridY;
    public bool isDiggable = false;
    public bool canDropItem = false;
    public bool canPlaceFurniture = false; 
    public bool isNPCObstacle = false;
    public int daysSinceDug = -1;//被锄头砸
    public int daysSinceWatered = -1;//浇过水没
    public int seedItemCode = -1;//种子id
    public int growthDays = -1;//种植天数
    public int daysSinceLastHarvest = -1;//重复收获的植物距离上次收获的天数
   public GridPropertyDetails()
    {

    }
}

存储信息的工具

我们要用ScriptableObject来把上述的格子信息存储下来,方便之后foreach循环判定整个格子的信息,有的小伙伴会说 那我们直接用list给它存下来不久可以了吗,我只想说你想到太简单了,如果我们用List来存储它的话,一个场景格子有成千上万个,难道要一个一个的给他们赋值格子类型吗,显然是不现实的,所以我们要先把这些信息用工具存下来,利用tilemap来设置各个格子的信息,如果你看到这些还不明白的话,不要担心,到了下面你就会明白我将的做法
现在我们先来把代码搞出来

using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName ="so_GridProperties",menuName = "Scritable/Properties")]
public class SO_GridProperties : ScriptableObject
{
    public SceneName sceneName;
    public int gridWidth;
    public int gridHeight;
    public int originX;
    public int originY;
    [SerializeField]
    public List<GridProperty> gridPropertyList ;
}

这样我们右键Scritable->Properties就可以创建出来一个so_GridProperties
SceneName是场景名字 比如 农场,空地,卧室等
gridWidth格子的总宽度,
gridHeight 格子的总高度
originX x轴的偏移
originY y轴的偏移
gridPropertyList 是格子的详细信息
注意:originX originY的偏移是基于左下角格子的坐标而定的
在这里插入图片描述
比如我这个场景里左下角的各自坐标是-40,-30那么我这个的偏移就是-40,-30

记录格子信息

好啦,现在我们到很关键的一步了 记录各个格子的信息 ,这个功能只能在编译器中执行
前置:我们为GridBoolProperty枚举中的五个模式分别创建出五个对应的tilemap
思路 :在编译器模式下,启用(gameobject.setactive=true)的时候就把SO_GridProperties里面的格子信息List清空,弃用(gameobject.setactive=false)的时候就循环整个tilemap,如果tile不为空就把它存到SO_GridProperties的List中

例子

比如我想要规划某个位置是可以种地的地方 那么我就要把种地这个位置的tilemap启用,在想要让它种地的位置画上图,然后再将它的setActive设为false 他就会自动保存到List中了
1、启用Diggable在这里插入图片描述2画图 蓝色框就是可以种植物品的位置在这里插入图片描述
3把它关闭在这里插入图片描述
4 自动被保存到这里啦 我们可以循环这个文件就可以操作整个场景了
在这里插入图片描述

代码

思路讲好了 上代码!!!

using UnityEditor;
using UnityEngine;
using UnityEngine.Tilemaps;
[ExecuteAlways]
public class TileMapGridProperty : MonoBehaviour
{
#if UNITY_EDITOR
    private Tilemap tilemap;
    [SerializeField] private SO_GridProperties gridProperties = null;
    [SerializeField] private GridBoolProperty gridBoolProperty = GridBoolProperty.diggable;
    private void OnEnable()
    {
        if (!Application.IsPlaying(gameObject))
        {
            tilemap = GetComponent<Tilemap>();
            if (gridProperties != null)
                gridProperties.gridPropertyList.Clear();
        }
    }
    private void OnDisable()
    {
        if (!Application.IsPlaying(gameObject))
        {
            UpdateGridProperties();
            //用于将目标对象标记为已更改,这通常是在修改了对象的属性但不希望创建撤销记录的情况下使用
            if (gridProperties != null)
                EditorUtility.SetDirty(gridProperties);
        }
    }

    private void UpdateGridProperties()
    {
        tilemap.CompressBounds();//将 tilemap的origin 和 size 压缩到瓦片所存在的边界。
        if (!Application.IsPlaying(gameObject))
        {
            if (gridProperties != null)
            {
                Vector3Int startCell = tilemap.cellBounds.min;
                Vector3Int endCell = tilemap.cellBounds.max;
                for(int x = startCell.x; x < endCell.x; ++x)
                {
                    for(int y = startCell.y; y < endCell.y; ++y)
                    {
                        TileBase tile = tilemap.GetTile(new Vector3Int(x, y, 0));
                        if (tile != null)
                            gridProperties.gridPropertyList.Add(new GridProperty(new GridCoordinate(x, y), gridBoolProperty, true));
                    }
                }
            }
        }
    }
#endif
}

这个功能要在编译器中才可以使用,标记为[ExecuteAlways]
把它拖拽到tilemap上就可以实现我刚才将的操作啦~
简单讲一下代码逻辑吧
在启用这个gameobject的时候就把整个List清空
在禁用这个gameobject的时候就循环整个tilemap 把有画图的格子存下来,gridBoolProperty为格子的类型(种地的?可以丢弃物品的?等等)

尾声

好拉,时间不早代码刚好,今天的代码很简单,明天要上班不能熬夜写太多不然明天起不来又要扣钱,外包狗的悲哀(/(ㄒoㄒ)/~~),希望大家好好理解一下这个代码,千万不要去外包,没人权呐!
下周我来讲一下如何使用这个格子信息来种地 锄地 种树等功能,我们下周不见不散啦~

### 关于《星露谷物》与 Unity 引擎 《星露谷物》最初并非基于 Unity 引擎开发,而是采用 C# 编程言并利用 MonoGame 框架构建[^1]。MonoGame 是一个开源框架,旨在帮助开发者创建可在多个平台上运行的游戏。 然而,在社区中存在一些项目尝试通过不同方式将该游戏移植到其他环境中或者为其创建模组工具链来支持更多功能扩展。对于希望使用 Unity 来制作《星露谷物》模组的情况来说,这通常意味着要寻找第三方解决方案或自己动手实现桥梁接口以便让两个环境之间能够交互工作。 如果考虑在 Unity 中重新创造类似的体验,则可以充分利用该引擎的强大之处来进行高效的内容创作和管理;而对于想要直接修改原版游戏行为而不改变其核心架构的人来说,官方推荐的方式还是遵循现有的 Modding API 进行操作而不是转向另一个完全不同的技术栈。 ```csharp // 示例:这是如何在一个简单的 Unity 脚本里加载外部资源的方法之一 using UnityEngine; using System.Collections; public class LoadExternalResource : MonoBehaviour { IEnumerator Start () { WWW www = new WWW ("file://path_to_mod_resource"); yield return www; Texture texture = www.texture; Renderer renderer = GetComponent<Renderer>(); renderer.material.mainTexture = texture; } } ``` 尽管如此,《星露谷物》本身并不依赖 Unity 引擎,因此任何关于在其基础上增加新特性的工作都需要额外的努力去建立两者之间的连接机制或者是独立地模仿原有风格设计新的作品。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值