Skip to content

115. 实战:酷家乐装修编辑器(十九)

Published:

上节把家具的平移、旋转等编辑功能实现了:

2025-06-29 14.00.21.gif

这节我们把编辑后的 position、rotation 存入 store 中,并且在 2d 视图中把它画出来。

因为后面可能添加多个,我们给每个家具一个唯一的 id:

image.png

image.png

渲染家具的时候设置 name:

image.png

gltf.scene.name = furniture.id

这样更新的时候就可以根据 id 查找了。

添加一个更新家具的方法:

image.png

export interface Action {
    setData(data: State['data']): void;
    updateFurniture(id: string, type: 'position' | 'rotation', info: Vector3): void;
}
updateFurniture(id, type, info) {
    set(state => {
        return {
            ...state,
            data: {
                ...state.data,
                furnitures: state.data.furnitures.map(item => {
                    if(item.id === id) {
                        if(type === 'position') {
                            item.position.x = info.x;
                            item.position.y = info.y;
                            item.position.z = info.z;
                        } else {
                            item.rotation.x = info.x;
                            item.rotation.y = info.y;
                            item.rotation.z = info.z;
                        }
                    }
                    return item;
                })
            }
        }
    })
}

然后改变位置、旋转角度的时候更新下 store:

image.png

image.png

把这个更新方法传入 init3D

updateFurniture: Action['updateFurniture']

change 的时候调用下来更新 store:

image.png

光这样还不行,现在有个严重的问题。

因为 data 一变,就会删除整个场景:

image.png

我们得区分这是改变家具而不是清空数据:

image.png

加个判断就好了

if(data.walls.length) {
    return;
}

同样,渲染 house 的时候也要判断,如果已经有了,那就是更新家具:

image.png

const houseObj = scene.getObjectByName('house')!;
if(houseObj) {
    data.furnitures.forEach(furniture => {
        const obj = houseObj.getObjectByName(furniture.id);

        if(obj) {
            obj.position.set(
                furniture.position.x,
                furniture.position.y,
                furniture.position.z
            );

            obj.rotation.x = furniture.rotation.x;
            obj.rotation.y = furniture.rotation.y;
            obj.rotation.z = furniture.rotation.z;
        }
    })
    return;
}

为了观察 json 是不是变了,我们把它渲染出来:

image.png

const { data } = useHouseStore();
<pre>
    {JSON.stringify(data.furnitures, null, 4)}
</pre>

试一下:

2025-06-29 20.52.54.gif

平移和旋转家具的时候,可以看到 store 里的数据确实改变了。

这样,编辑家具到保存到 json 里就都完成了。

但现在编辑的数据刷新就没了:

2025-06-29 20.56.55.gif

我们加一下 store 的持久化:

image.png

image.png

const stateCreator: StateCreator<State & Action> = (set, get) => {
};

const useHouseStore = create<State & Action>()(persist(stateCreator, {
    name: 'house'
}));

试下效果:

2025-06-29 21.02.43.gif

现在编辑完刷新页面依然保存着编辑后的结果。

在 localStorage 里也能看到保存的数据:

image.png

这样,数据持久化就完成了。

案例代码上传了小册仓库

总结

这节我们做了编辑结果保存到 store 的功能。

我们在 store 添加了一个更新家具信息的方法,给家具一个 id。

改变家具位置、角度的时候调用这个方法来更新 json 里的家具信息。

要注意的是之前清空数据、渲染房屋都是监听 data 的变化,改了家具也会改 data,会不断触发清空数据,所以我们要处理下,判断出这种情况。

家具编辑的结果保存好后,下节我们把家具同步渲染到 2D 视图。

评论