笨木头  2021-12-28 09:11         阅读(1374)     评论(0)
转载请注明,原文地址: http://www.benmutou.com/archives/2931
文章来源:笨木头与游戏开发

还有一个比较重要的问题没有解决,那就是,渲染的时候,坐标怎么办?如何去更新GameObject的坐标,毕竟渲染都靠Html元素,Html元素可没有什么现成的坐标系可以用。

 

1.RelativeAbsolute组合

类似游戏里的坐标系,我们要怎么实现?毕竟html元素基本上是靠marginfloattablefixed这些来布局的。

这个问题一开始我也有点困扰,但最终我找到了一个目前来说还算不错的解决方案。

我们先给GameWorld组件套一层div,并且这个divpositionrelative的:

<div class="bgDiv" style="position: relative;">
	<GameWorld @ref="@_gameWorld" />
</div>

 

然后,我们所有的游戏对象渲染组件都把position设为absolute,这样话,我们的游戏对象的坐标就通过lefttop来设置(分别对应xy坐标),并且这些对象的坐标都是相对于上一级的元素进行绝对布局的。

最后,GameWorld里渲染游戏对象的时候,不区分上下级,也就是说:所有游戏对象渲染时都是平铺,都是同一个层级的。

比如,理论上游戏对象应该是这样渲染的:

<div id="英雄">
	<div id="血量条" />
</div>

 

实际上,我们是这样渲染的:

<div id="英雄"/>
<div id="血量条" />

 

于是,我们只需要计算出每一个游戏对象的“世界坐标”,就可以方便地渲染,而不需要考虑他们的上下级关系了。

也许大家会疑惑,按照理论上的那种渲染关系,也可以方便的渲染,只要获取到子对象的“本地坐标”(以父对象作为起始点的相对坐标)即可。

其实也没错,这样也是可以的,但,可能是我个人的喜好,我认为平铺渲染更接近于Canvas的那种模式,渲染不考虑父子关系,父子关系交给游戏对象本身去管理。不过,这个看大家个人的喜好吧,我只是提供一种参考方案。

 

2.渲染

总结一下,实际上整个游戏的渲染流程是这样的,在GameContext里,每一帧做了以下逻辑:

    public async ValueTask Step(float elapsedTime)
    {
        // 移除已销毁的对象
        GameObjects.RemoveAll(t => t.IsDestroy);

        // 调用所有GameObject的Update函数
        await Update();

        // 碰撞检测
        CheckCollision();

        // 更新对象的渲染规格
        UpdateGameObjectRenderRect();
    }

 

先更新GameObject的逻辑,然后检测碰撞,最后更新游戏对象的渲染规格(坐标、大小),Step执行完后,就会调用GameWorldRefresh函数(执行了StateHasChanged),刷新渲染。

 

关于更新游戏对象的渲染规格,其实我还没有封装好,算是比较初级的实现,大家也不用太在意,可以随时用自己的逻辑替换。

 

3.结束

总的来说,到目前为止,我算是把遇到的关键问题给解释了一遍了,剩下的代码都是一些游戏逻辑的代码。像碰撞检测、直线行走、子弹攻击、动画啥的,没有什么固定的套路,大家就随便看看就好。

毕竟这是我第一次用Blazor来实现游戏的功能,还是一个比较简单的功能。

 

如果大家在“不使用Canvas来进行Blazor游戏开发”这个事情上,有更好的解决方案的话,希望能指点一下我,非常感谢。

 

 

0 条评论
发表评论
粤ICP备16043700号

本博客基于 BlazorAnt Design Blazor 开发