ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

“笨办法”学Python 3基础篇 - 搭建简易的网站

2021-05-07 16:03:10  阅读:268  来源: 互联网

标签:paths death 笨办法 room name Python Scene scene 搭建


“笨办法”学Python 3基础篇系列文章

“笨办法”学Python 3基础篇 第一部分-打印与输入
“笨办法”学Python 3基础篇 第二部分-文件操作
“笨办法”学Python 3基础篇 第三部分-函数
“笨办法”学Python 3基础篇 第四部分-数据容器与程序结构
“笨办法”学Python 3基础篇 第五部分-面向对象的类
“笨办法”学Python 3基础篇 第六部分-项目骨架与自动测试
“笨办法”学Python 3基础篇 第七部分-搭建简易的网站


搭建简易的网站


前言

终于来到了本系列的最后一篇了,有点小兴奋。虽然中间间隔了很多时间,但每一次码字都让我懂得了坚持和总结带来的好处,都能够再一次地对原来储存在脑海中某个角落的知识进行重构,变成自己知识大厦中的地基,脑子也在每次总结中进行了一次精神地“按摩”。
在本文中,我将用面向对象的编程方法编写一个对话类的三体小游戏(章北海作为主角),并通过flask创建简单的游戏网站(目前只学到这)。

7.1 Web框架-flask安装和项目创建

要使用网站服务,需要安装一个“Web”框架,减少开发负担。在书中,主要介绍了flask框架的应用。在激活虚拟环境后,通过

pip install flask

实现安装,安装过程如下图:
installflask
flask安装完成后,需要创建一个threebody项目,在PowerShell中输入如下命令:

cd projects
mkdir threebody
cd threebody
mkdir bin
mkdir threebody
mkdir tests
mkdir docs
mkdir templates
new-item -type file .\threebody\__init__.py
new-item -type file .\tests\__init__.py

与之前项目创建不同的是,新建了一个名为“templates”的目录,用于存放网站的html模板。

7.2 利用面向对象方法设计三体游戏

在threebody\threebody目录下新建一个game.py作为三体游戏的主程序。整个三体游戏的设计思路是通过场景切换进行的,游戏者通过做出选择进入不同剧情,类似《秋之回忆》之类的游戏。程序的核心为类Scene的设计,代码具体为:

class Scene:
    """基本场景类"""
    def __init__(self, name, description):
        self.name = name
        self.description = description
        self.paths = {}
    
    def enter(self, direction):
        return self.paths.get(direction, None)

    def add_paths(self, paths):
        self.paths.update(paths)

每个场景作为对象对类Scene进行初始化。初始化时渲染场景的名字和剧情描述,并初始化决定剧情走向的字典paths。通过enter(direction)函数返回direction指定的场景对象,通过add_paths(paths)函数来更新剧情走向字典paths,从而建立不同场景对象的剧情联系。关于剧情的走向脉络如下图所示:
游戏剧情
游戏剧情从自然选择号开始,到太空陵墓结束。中间每个场景如果选择错误,就会进入死亡场景(根据剧情不同,死亡场景还需要细分)。在死亡场景中可以通过选择play again重玩游戏。这一剧情流向通过Scene中的add_paths实现。具体代码如下:

natureSelectionFleet.add_paths({
    '1': death_1_1,
    '2': death_1_2,
    '3': death_1_3,
    '4': escape,
    '*': natureSelectionFleet 
})

escape.add_paths({
    '1': death_2,
    '2': death_2,
    '3': death_2,
    '4': control_terminal,
    '*': escape
})       
        
control_terminal.add_paths({
    '1': extrasolar,
    '2': death_3,
    '3': death_3,
    '4': death_3,
    '*': control_terminal
})

extrasolar.add_paths({
    '1': fleet_earth, 
    '2': death_2,
    '3': death_4,
    '*': extrasolar
})

fleet_earth.add_paths({
    '1': death_2,
    '2': ultimate_rule_fleet,
    '3': ultimate_rule_fleet,
    '*': fleet_earth
})

ultimate_rule_fleet.add_paths({
    '1': blue_space_fleet,
    '2': death_6,
    '3': death_5,
    '4': death_2,
    '*': ultimate_rule_fleet
})

blue_space_fleet.add_paths({
    '1': last_episode,
    '2': death_6,
    '*': blue_space_fleet
})

这里的*代表玩家的无效输入,无效输入时,剧情场景不切换,停留在原场景中。剩下的工作是设计不同的场景对象,具体的代码为:

#自然选择号死亡场景
death1 = """
        自然选择号在与三体文明'水滴'探测器的激战中被摧毁......
         """

death_1_1 = Scene("游戏失败",
f"""
原来你也接收了思想钢印。
警卫员!
马上逮捕章北海!

{death1}
""")
      
death_1_2 = Scene("游戏失败",
f"""
章北海,你这个懦夫!
你的内心充分暴露出来了,表面是个人类必胜论者,
内心确是一个失败论者。
警卫员!
马上逮捕章北海!

{death1}
""")

death_1_3 = Scene("游戏失败",
f"""
你是云天明?
警卫员!
马上通知地球舰队!

{death1}
""")

death_2 = Scene("游戏失败", death1)

death_3 = Scene("游戏失败", 
f"""
飞船控制失败!

{death1}
"""
)

death_4 = Scene("游戏失败", 
f"""
东方延绪:
        章北海, 我代表星舰地球逮捕你。
        全员准备,返航迎击三体人的探测器。

        {death1}
""")

death_5 = Scene("游戏失败",
f"""
在更改航线后,遭遇了三体文明的舰队,被击毁...
""")

death_6 = Scene("游戏失败",
f"""
遭遇了黑暗森林法则,被星舰地球中的其它战舰次声波核弹攻击,
全员阵亡!
""")

#自然选择号
natureSelectionFleet = Scene("自然选择号", 
"""
东方延绪:
        章北海执行舰长,我是自然选择号的舰长东方延绪。欢迎您。
        现在我把自然选择号的指挥权交给您。飞船有四种前进模式,
        当进入前进4模式时,船员必须进入睡眠仓。现在,我需要
        再次确认您是否受到思想钢印的影响,请您回答我这个问题:
        '人类是否必胜?'
        [1] 必胜
        [2] 必败
        [3] 这要取决于我所见到的三体文明
        [4] 人的意志胜过一切
""")

#逃离太阳系
escape = Scene("自然选择号战舰控制中心",
"""
东方延绪:
        章北海舰长,现在我交出自然选择号的控制权。据地球舰队传来的最新消息:
        三体文明的探测器-水滴-已经抵达太阳系的边缘,15分钟后将与地球舰队接触。
        现在飞船等待您发布第一条命令:
        [1] 前进1 逃离太阳系
        [2] 前进2 逃离太阳系
        [3] 前进3 逃离太阳系
        [4] 前进4 逃离太阳系
""")

#飞控终端
control_terminal = Scene("自然选择号战舰飞控终端","""
警告!
警告!
警告!
飞船进入前进4必须通知所有船员进入深海睡眠模式。请输入飞控密码:
[1] Man Always Remember Love Because Of Romance Only
[2] If You Give Me A Pivot Point I Could Move The Earth
[3] The Sun Rather Than The Earth At The Center Of The Universe
[4] Two Heads Are Always Better Than One
""") 

# 太阳系外
extrasolar = Scene("自然选择号战舰","""
飞船已经飞出了太阳系,身后的蓝色空间号、深空号、终极规律号以及企业号正在追击。
下一步命令是:
[1] 延续人类文明,向前飞,向远飞
[2] 掉头击毁追击战舰
[3] 将舰队指挥权交给东方延续舰长
"""
)

# 星舰地球
fleet_earth = Scene("星舰地球","""
地球舰队已经被水滴摧毁.......
五艘战舰必须延续文明的责任,太空将是我们最后的归宿。星舰地球决定:
[1] 处决人类的叛徒章北海,回去与水滴战斗
[2] 处决人类的叛徒章北海,继续飞往十八光年外的天鹅座NH558J2
[3] 章北海是英雄,继续飞往十八光年外的天鹅座NH558J2
"""
)

#终极规律号
ultimate_rule_fleet = Scene("终极规律号","""
终极规律号战舰中出现了一种不安的气氛......
十四光年,飞船的资源是有限的,如何得到补给?
舰长,我们该怎么办?
[1] 向其它四艘战舰发射次声波氢弹
[2] 向其它四艘战舰求援,请求补给
[3] 要求星舰地球更改航程,找到补给点
[4] 回地球吧
"""
)

#蓝色空间号
blue_space_fleet = Scene("蓝色空间号","""
警告!
警告!
警告!
终极规律号的次声波氢弹冲击波即将到达....
防御成功,舰队损伤5%...
等待下一步命令:
[1] 发射高能伽马射线激光击毁终极规律号
[2] 逃离
""")

#最后的场景
last_episode = Scene("太空陵墓","""
蓝色空间号带走了所有的燃料和配件,并将自然选择号、企业号、深空号的
残骸切割多段,围城巨石阵,构建了一处太空陵墓,纪念人类第一次体会到
宇宙‘黑暗森林’的可怕。

恭喜你,顺利通过了剧情!
"""
) 

START = 'natureSelectionFleet'
# 返回场景名字对应的场景对象
def load_scene(name):
    return globals().get(name) 
# 返回场景对象对应的场景名字
def name_scene(scene):
    for key, value in globals().items():
        if value == scene:
            return key

7.3 编写game.py的自动测试脚本

接下来,将编写game.py的自动测试脚本。在tests\目录下新建game_tests.py,测试工具仍然为nosetests。分别对game.py中Scene的初始化函数、add_paths和enter函数进行测试。具体代码为:

from nose.tools import *
from threebody.game import *


def test_scene():
    gold = Scene("GoldRoom",
                """This room has gold in it you can grab. 
                There's a door to the north.""")
    assert_equal(gold.name, "GoldRoom")
    assert_equal(gold.paths, {})

def test_add_enter_paths():
    center = Scene("Center", "Test room in the center.")
    north = Scene("North", "Test room in the north.")
    south = Scene("South", "Test room in the south.")

    center.add_paths({'north': north, 'south': south})
    assert_equal(center.enter('north'), north)
    assert_equal(center.enter("south"), south)


def test_game_map():
    start_room = load_scene(START)
    assert_equal(start_room.enter('1'), death_1_1)
    assert_equal(start_room.enter('2'), death_1_2)
    assert_equal(start_room.enter('3'), death_1_3)
    assert_equal(start_room.enter('4'), escape)
    assert_equal(start_room.enter('*'), natureSelectionFleet)

需要注意的是,在引入特性时,需要从threebody\game.py中引入所有提到的类和全局变量。PowerShell中的测试结果为:
gametests

7.4 编写HTML模板

在三体游戏中,我们采用了布局模板和POST表单。在templates\目录下创建show_room.html和layout.html两个文件。布局模板代码为:

<html>
    <head>
        <title>三体游戏</title>
    </head>
    <body>
        {% block content %}

        {% endblock %}
    </body>
</html>

主要包含标题“三体游戏”。POST表单代码为:

{% extends "layout.html" %}

{% block content %}

<h1>{{ room.name }}</h1>

<pre>
    {{ room.description }}
</pre>

{% if room.name == "游戏失败"%}
    <p><a href="/">Play Again?</a></p>
{% elif room.name == "太空陵墓" %}
    <p><a href="/">退出游戏</a></p>
{% else %}
    <p>
        <form action='/play' method='POST'>
            - <input type='text' name='action'><input type='SUBMIT'>
        </form>
    </p>    
{% endif %}

{% endblock %}

在这个html文件中,首先加载布局模板,其次将场景对象的名字和剧情描述显示在网页上。随后启用 if-else 条件判断语句,当检测到场景名为“游戏失败”的字符串时,在剧情描述底部显示 “play again?”;当检测到场景名为“太空陵墓”的字符串时,在剧情描述底部显示“退出游戏”;否则就显示文本框,等待用户输入信息推动剧情发展。

7.5 创建三体web游戏引擎

游戏引擎的python文件应创建在项目主目录下,即第一个threebody目录下。我创建了一个名为app.py的web引擎文件。主要引用了flask网络框架中的FLASK, session, redirect,url_for, request,render_template特性。当然,为了运行游戏,还需要引入game.py。具体代码如下:

from flask import Flask, session, redirect, url_for, request
from flask import render_template
from threebody import game

app = Flask(__name__)

@app.route("/")
def index():
    #this is used to "setup" session with starting values
    session['scene_name'] = game.START #利用会话临时存储场景名字
    return redirect(url_for("play"))


@app.route("/play", methods=['POST', 'GET'])
def play():
    scene_name = session.get('scene_name') #获得当前场景的名字

    if request.method == 'GET':
        room = game.load_scene(scene_name) #通过场景的名字加载场景对象
        return render_template("show_room.html", room=room)    
 
    else:
        action = request.form.get('action')
        
        if scene_name and action:
            room = game.load_scene(scene_name)
            next_scene = room.enter(action) #获取下一个场景的对象
            if not next_scene:
                next_scene = room.enter('*')
                #将下一个场景的名字存在临时会话中,供web服务器使用
                session['scene_name'] = game.name_scene(next_scene)
            else:
                session['scene_name'] = game.name_scene(next_scene)
        return redirect(url_for("play"))

# YOU SHOULD CHANGE THIS IF YOU PUT ON THE INTERNET
app.secret_key = 'sdjffiweriwuer923riew3shfs'

if __name__ == "__main__":
    app.run()

程序的第一个主要函数为index(), 代表了主目录“/”,使用了session临时会话来存储场景名字,以工下次调用时使用。返回“/play"目录。程序第二个主要函数为play()。在"/play"目录下有两种模式POST或GET,当未获得用户输入时,默认为GET,此时引擎加载show_room.html文件。当用户输入有效信息后,进入post模式,此时引擎根据信息得到下一个剧情场景,并存储在session会话中,返回play目录进行下一场景加载。最后,通过app.run()语句来自动运行web游戏引擎。

7.6 游戏运行效果

在Poweshell中,运行

python app.py

结果为:
启动flask
此时debug模式是关闭的,如果要打开,则将app.run()修改为app.run(debug = True)。在本地网页端运行时,根据提示,在浏览器上输入localhost:5000/即可。效果如下图:
效果图

结语

这是CSDN上自己写的第一个系列的文章,内容虽然没有什么新意,但坚持写作,把自己的思路理的非常清晰,也知道了什么地方还没有掌握。接下来,要沉静一段时间,继续学习,坚持写作。

标签:paths,death,笨办法,room,name,Python,Scene,scene,搭建
来源: https://blog.csdn.net/cslg_awq/article/details/116452611

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有