python3+libtcod學習(三)繪製地圖

上一篇 python3+libtcod學習(二)移動符號

面向對象

爲了解決系統的可維護性,可擴展性,可重用性,現在需要修改之前的代碼。
首先設計的這個類代表這個遊戲中的所有實體,無論是主角、NPC、敵人,這些在屏幕上看得到的“實體”都會屬於這個類。創建一個新文件entity.py輸入以下代碼:

class Entity:
    def __init__(self, x, y, char, color):
        self.x = x
        self.y = y
        self.char = char
        self.color = color

    def move(self, dx, dy):
        self.x += dx
        self.y += dy

這個類中包含了一些最基本的信息和功能,現在來修改之前的engine.py代碼

import tcod as libtcod

from entity import Entity
from input_handlers import handle_keys


def main():
    screen_width = 80
    screen_height = 50
	# 0.創建可操控的白色的“主角”和一個黃色的NPC
    player = Entity(int(screen_width / 2), int(screen_height / 2), '@', libtcod.white)
    npc = Entity(int(screen_width / 2 - 5), int(screen_height / 2), '@', libtcod.yellow)
    entities = [npc, player]
	...
	...
    while not libtcod.console_is_window_closed():
        libtcod.sys_check_for_event(libtcod.EVENT_KEY_PRESS, key, mouse)
        libtcod.console_set_default_foreground(con, libtcod.white)
        # 1.注意這裏和下面的座標都已經改爲player.x和player.y
        libtcod.console_put_char(con, player.x, player.y, '@', libtcod.BKGND_NONE)
        libtcod.console_blit(con, 0, 0, screen_width, screen_height, 0, 0, 0)
        libtcod.console_flush()
        libtcod.console_put_char(con, player.x, player.y, ' ', libtcod.BKGND_NONE)

        action = handle_keys(key)
        
        move = action.get('move')
        exit = action.get('exit')
        fullscreen = action.get('fullscreen')
        
        if move:
            dx, dy = move
            # 2.這裏修改了移動的方式
            player.move(dx, dy)
        
        if exit:
            return True
        
        if fullscreen:
            libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen())
            

if __name__ == '__main__':
    main()

現在我們還需要一個用於“繪製”和“清除”的函數。創建一個名爲的新文件render_functions.py,寫下以下代碼:

import tcod as libtcod

# 這個函數的參數分別是控制檯、一個要進行繪製的隊列、屏幕的寬、高
def render_all(con, entities, screen_width, screen_height):
    # 把列表中的實體取出進行繪製
    for entity in entities:
        draw_entity(con, entity)
    libtcod.console_blit(con, 0, 0, screen_width, screen_height, 0, 0, 0)
    
# 刪除
def clear_all(con, entities):
    for entity in entities:
        clear_entity(con, entity)

# 對實體進行繪製
def draw_entity(con, entity):
    libtcod.console_set_default_foreground(con, entity.color)
    libtcod.console_put_char(con, entity.x, entity.y, entity.char, libtcod.BKGND_NONE)

# 刪除在屏幕上的實體
def clear_entity(con, entity):
    libtcod.console_put_char(con, entity.x, entity.y, ' ', libtcod.BKGND_NONE)

有了上面的代碼再來修改engine.py中的代碼:

...
	libtcod.sys_check_for_event(libtcod.EVENT_KEY_PRESS, key, mouse)
	# 繪製
	render_all(con, entities, screen_width, screen_height)
	libtcod.console_flush()
	# 刪除
	clear_all(con, entities)
	action = handle_keys(key)
...

注意還需要import clear_all和render_all函數,現在運行程序,應該可以看到你的白色’@'符號和一個代表NPC的黃色‘@’符號。

創建地圖

創建一個tile.py文件並將以下代碼放入其中:

class Tile:
    """
    這個類的作用是給組成地圖的字符(區塊)一些性質,現在這裏只寫下了是否被阻塞和是否遮擋視野,也就是‘牆’的意思
    """
    def __init__(self, blocked, block_sight=None):
        self.blocked = blocked
        # 默認一個區塊如果可以阻攔玩家前進就阻攔視野,如果不想要這樣的效果就傳入block_sight的值
        if block_sight is None:
            block_sight = blocked
        
        self.block_sight = block_sight

現在有了地圖的組成部分,可以寫下地圖類了,創建一個文件game_map.py:

from tile import Tile


class GameMap:
    def __init__(self, width, height):
        self.width = width
        self.height = height
        self.tiles = self.initialize_tiles()

    def initialize_tiles(self):
    	# 直接生成一個二維數組保存地圖,這是一張空地圖。
        tiles = [[Tile(False) for y in range(self.height)] for x in range(self.width)]
		# 給一些地方加上‘牆’,這裏只是爲了演示目的,可以隨便修改。
        tiles[30][22].blocked = True
        tiles[30][22].block_sight = True
        tiles[31][22].blocked = True
        tiles[31][22].block_sight = True
        tiles[32][22].blocked = True
        tiles[32][22].block_sight = True
        return tiles
    
    #既然有‘牆’的存在,就不讓玩家通過    
    def is_blocked(self, x, y):
        if self.tiles[x][y].blocked:
            return True

        return False

下一步要繪製地圖,來到render_functions.py中,修改繪製函數:

...
def render_all(con, entities, game_map, screen_width, screen_height, colors):
	# 繪製地圖
    for y in range(game_map.height):
        for x in range(game_map.width):
            wall = game_map.tiles[x][y].block_sight

            if wall:
                libtcod.console_set_char_background(con, x, y, colors.get('dark_wall'), libtcod.BKGND_SET)
            else:
                libtcod.console_set_char_background(con, x, y, colors.get('dark_ground'), libtcod.BKGND_SET)
    
    # 繪製實體的部分依然不變
    for entity in entities:
        draw_entity(con, entity)

    libtcod.console_blit(con, 0, 0, screen_width, screen_height, 0, 0, 0)
...

最後回到engine.py文件,進行一些更改。

...
	screen_height = 50
    # 設置地圖大小、相關區域顏色
    map_width = 80
    map_height = 45
    colors = {
        'dark_wall': libtcod.Color(0, 0, 100),
        'dark_ground': libtcod.Color(50, 50, 150)
    }

    player = Entity(int(screen_width / 2), int(screen_height / 2), '@', libtcod.white)
...
...
	con = libtcod.console_new(screen_width, screen_height)
    # 創建地圖
    game_map = GameMap(map_width, map_height)
    key = libtcod.Key()
...
...
    while not libtcod.console_is_window_closed():
        libtcod.sys_check_for_event(libtcod.EVENT_KEY_PRESS, key, mouse)
        # 繪製地圖和實體
		render_all(con, entities, game_map, screen_width, screen_height, colors)
		libtcod.console_flush()
		clear_all(con, entities)
		action = handle_keys(key)
        
        move = action.get('move')
        exit = action.get('exit')
        fullscreen = action.get('fullscreen')
        
        if move:
            dx, dy = move
            # 如果有‘牆’則不能移動
            if not game_map.is_blocked(player.x + dx, player.y + dy):
                player.move(dx, dy)
...

這時候運行程序我們可以看到屏幕上出現了一堵無法穿越的小牆。

下一篇 python3+libtcod學習(四)生成地牢

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章