面向對象
爲了解決系統的可維護性,可擴展性,可重用性,現在需要修改之前的代碼。
首先設計的這個類代表這個遊戲中的所有實體,無論是主角、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)
...
這時候運行程序我們可以看到屏幕上出現了一堵無法穿越的小牆。