用python3从零开始开发一款烧脑射击游戏#3

上回说到我们已经可以控制小方块的移动了,现在我们要把这个小方块放置到游戏场景里
剥去美术的外壳,游戏场景其实就是一个标记了玩家可行走与不可行走的空间
对于2D游戏,它是一个平面网格,3D游戏就是一个3维空间网格

我们先来看2D的情况:

首先我们用一个二维数组记录地图上所有像素坐标点(整数坐标点)的可行走与不可行走的信息
grid_map = [[0 for i in range(M)] for i in range(N)]

地图中的阻挡就是一块连续的不可行走区域
以最简单的矩形阻挡为例,我们定义一个类来描述一个阻挡:

class Block(object):
    def __init__(self,x,y,w,h):
        self.rect = Rect(x,y,w,h)
        for i in range(y,y+h):
            for j in range(x,x+w):
                grid_map[i][j]=1

在构造函数中把二维数组中对应的元素标记为不可行走(0可行走,1不可行走)
这样我们每构造一个Block类的对象,就在地图上生成了一个阻挡

我们在地图初始化中创建所有的阻挡

def InitMap():
    for i in range(N):
        for j in range(M):
            grid_map[i][j]=0#初始化地表,都是可行走
            
    for i in range(0,M,50):#创建若干阻挡
        b1 = Block(i,0,10,100)
        b2 = Block(i,200,10,100)
        b3 = Block(i,400,10,100)
        block_list.append(b1)
        block_list.append(b2)
        block_list.append(b3)

如果绘制出来,将得到这样的一张地图,黑色的是可行走区域,灰色的表示阻挡块


二维地图.png

接下来我们再让这些阻挡能够真的影响玩家的移动

假设玩家出生时不会出生在阻挡里
那么我们只需要在表示玩家的矩形发生移动时,判断矩形边界上的点是否都在可行走区域即可

onblock = 0
#分别判断两条横边和两条竖边,tx,ty是矩形起始坐标点,20是默认边长
for i in range(tx,tx+20):
    if(grid_map[ty][i] or grid_map[ty+19][i]):
        onblock = 1
        break
for i in range(ty,ty+20):
    if(grid_map[i][tx] or grid_map[i][tx+19]):
        onblock = 1
        break

完整代码可以从这里获取

下面我们将把地图推广到3D空间

首先来感受一下游戏中会用到的3D地图的样子


3D地图.png

俯视图如下


俯视图.png

这是建模工具的展现方式。
我们在游戏里怎么通过2D视图来让玩家感受3D的空间呢?
重点来了,这也是这款游戏的核心玩点

玩家的主视角是当前高度的平面俯视图,通过地图的颜色来让玩家区分自己所处的地形:
地面:可自由移动(淡黄色表示)
阻挡:不可移动(灰色表示)
塌陷:走上去会下落到下一层,直到到达某一层的地面(黑色表示)
玩家可以自由切换到其他相邻高度,高度发生变化,平面俯视图也会相应变化

如图所示的一个空间区域(俯视图)
淡蓝色阻挡高度为1,深蓝色阻挡高度为2


地图.png

它在游戏中的表现如下,一共有3种不同的高度表现


20190124_154914.gif

现在我们用代码来实现这个空间
目前的版本不存在中空的“洞穴”,也就是说所有的阻挡如果存在,则一定是从第一层开始连续向上堆叠形成
在这个前提下我们就可以按下面的方式来定义一个空间内的阻挡:
a.在第一层的矩形投影
b.在空间上的高度H_block

而最后的活动空间,就是这些阻挡的“并集”以外的区域

class Block(object):
    def __init__(self,x,y,w,h,lv):#构造函数的参数表示投影矩形(x,y,w,h),以及阻挡的高度lv
        self.rect = Rect(x,y,w,h)
        self.lv = lv

        for k in range(lv):#遍历[0,lv-1]层
            for i in range(y,y+h):
                for j in range(x,x+w):
                    grid_map[k][i][j]=2#在[0,lv-1]层形成阻挡
                    
        for i in range(y,y+h):
            for j in range(x,x+w):
                if(0 == grid_map[lv][i][j]):#注意不能把已有的阻挡重算为平地
                    grid_map[lv][i][j]=1#在lv层形成地面   

我们需要在屏幕上绘制出这3种地形:

障碍物:比当前高度(H_cur)高的阻挡(H_block>H_cur)
平地:等于当前高度的阻挡(H_block==H_cur
塌陷区:没有阻挡的区域或阻挡高度小于当前高度(H_block

def DrawMap(lv):
    if lv > H :
        return
    for b in block_list:
        if(b.lv > lv):
            pygame.draw.rect(screen, color2, b.rect)
        elif b.lv == lv :
            pygame.draw.rect(screen, color1, b.rect)

最后我们再来看怎么操作玩家移动
在当前高度的移动与二维平面的移动一致(在上一篇中已经有讲述)
所以只需要实现如何改变玩家的高度
我的设计是这样的:
按z键后开始浮空,并立即飞到上一层,浮空状态时走到塌陷区不会下落
按x键后取消浮空,下落到能到达的最高地面

所以可以这样定义一个玩家类:

class Robot(object):
    def __init__(self):
        self.x = 10
        self.y = 10
        self.z = 0
        self.is_fly = 0#表示是否是浮空状态

再针对玩家的按键做对应的处理,就可以实现3维空间内的运动了

if (key_press[K_z]):
    self.is_fly = 1
    self.z += 1
elif (key_press[K_x]):
    self.is_fly = 0

完整的代码可以从这里获取

你可能感兴趣的:(用python3从零开始开发一款烧脑射击游戏#3)