2

我正在尝试用 Python 创建一个回合制策略游戏(想想 Dominion)。核心游戏对象和方法是其中包含方法的 Python 类(只是典型的 OO 东西)。UI 是一个使用 Bottle 的 HTML 客户端。我的目标是完全异步的方法。因此,唯一页面的内容是从 Python 对象生成的,我希望从页面提交以更新这些对象,而无需通过瓶子网络服务器返回页面(为此使用 jQuery AJAX)。

目前,我正在开发一个基本的聊天系统,该系统检索玩家编写的消息并将它们存储为聊天对象(包含玩家和文本数据,仅此而已)。然后将这些对象写入使用每秒更新一次窗口的 AJAX 的聊天窗口。聊天行的 HTML 格式是非常<div class="chatLine"><p>Player > </p><p>Text</p></div>标准的东西。

这个基本图可能会让它更清晰一些,即使它不是真正的技术,更概念化:


通讯周期图


我的 BottleUI.py(这是我运行以启动服务器的内容):

from Populate import *  # Everything in Populate can now be directly called.
# NOTE: Populate allows access to "bottle" and "Main"

# This ensures the css file is available
@route('/theCSS')
def static():
    return static_file('main.css', root='static')

@route('/citadel/:game/:player')
def gamePage(game, player):
    if not (game.isdigit()) or not (player.isdigit()):
        return "Invalid page."
    game = int(game)
    player = int(player)
    if ((game >= 0) and (game < listOfGames.__len__())) and ((player >= 0) and (player < listOfGames[game].listOfPlayers.__len__())):

        return '''

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" type="text/css" href="/theCSS">
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
    <!-- Sample AJAX script below, change as needed -->
    <script type="text/javascript">
        $(document).ready(function() {
            $('#chatForm').submit(function(e) {
                $.ajax({
                    type: 'POST',
                    url: "/AddToChat/''' + str(game) + '''/''' + str(player) + '''",
                    success: function() {
                        $('#chatInput').val("");
                    }
                });
                e.preventDefault();
            });
        });
        setInterval("updateChat();", 1000);
        $(function() {
            updateChat = function() {
                $('#chatText').load('/GenerateChat/''' + str(game) + '''');
            };
        });
    </script>
    <!-- Script to scroll to bottom of divs - needs to be changed into called function -->
    <script type="text/javascript">
        window.onload = function () {
             var objDiv = document.getElementById("gameFlow");
             objDiv.scrollTop = objDiv.scrollHeight;
             objDiv = document.getElementById("chatText");
             objDiv.scrollTop = objDiv.scrollHeight;
        };
    </script>
</head>
<body>
    <div id="container">
        <!-- Make this have background-image with the game number displaying programmatically -->
        <div id="banner">
            <h1>Citadel - Game ''' + str(game) + ''', Player ''' + str(player) + '''</h1>
        </div>
        <div id="main">
            <div id="leftPanel">
                <div id="playerTotals">
                    <h4>Player Totals:</h4>
                    <div id="totalsText">
                        <p>Money:</p>
                        <p>Population:</p>
                        <p>Troops:</p>
                        <p>Friend:</p>
                        <p>Enemy:</p>
                    </div>
                    <!-- Player totals go here (money, population/limit, troops, friend, enemy) -->
                    <div id="totalsNums">

                    </div>
                    <div class="clear"></div>
                </div>
                <div class="leftSegment">
                    <h4>Troop Cards:</h4>
                    <!-- Player's troopCards here -->
                    <select size=2>

                    </select>
                </div>
                <div class="leftSegment">
                    <h4>Territory Cards:</h4>
                    <!-- Player's territoryCards here -->
                    <select size=2>

                    </select>
                </div>
                <div class="leftSegment">
                    <h4>Region Cards:</h4>
                    <!-- Player's regionCards here -->
                    <select size=2>

                    </select>
                </div>
                <div class="leftSegment">
                    <h4>Resource Cards:</h4>
                    <!-- Player's resourceCards here -->
                    <select size=2>

                    </select>
                </div>
                <div class="leftSegment">
                    <h4>Diplomacy Cards:</h4>
                    <!-- Player's diplomacyCards here -->
                    <select size=2>

                    </select>
                </div>
                <div id="chatPane">
                    <form id="chatForm" method="POST" action="/AddToChat/''' + str(game) + '''/''' + str(player) + '''">
                        <textarea name="theChatText" id="chatInput"></textarea>
                        <input id="chatSubmit" class="button" type="submit" value="Send" />
                    </form>
                </div>
                <div class="clear"></div>
            </div>
            <div id="rightPanel">
                <!-- Game flow goes here (shows current player/phase, attacks with results, etc) -->
                <div id="gameFlow">

                </div>
                <!-- Player turn stuff goes here (changes depending on which phase, etc) -->
                <div id="playerActions">

                </div>
                <!-- Chat goes here (implement last) -->
                <div id="chatText">

                </div>
                <div class="clear"></div>
            </div>
        </div>
    </div>
</body>
</html>

    '''

    else:
        return "Invalid page."

run(host='localhost', port=8080)

这是我的 Populate.py(这是我的 AJAX @route 方法存储的地方):

    """
This module contains the bottle routs for AJAX population of the various parts
of the game page.
"""

from bottle import route, run, template, static_file, request
from Main import *  # Everything in Main can now be directly called.

globalBegin()

@route('/AddToChat/:game/:player', method='POST')
def AddToChat(game, player):
    theText = request.POST.get('theChatText', '').strip()
    game = int(game)
    player = int(player)
    listOfGames[game].listOfPlayers[player].addChat(theText)

@route('/GenerateChat/:game')
def GenerateChat(game):
    chatText = ""
    game = int(game)
    for line in listOfGames[game].chatList:
        chatText += '<div class="chatLine"><p>'
        chatText += line.player.name
        chatText += ' > </p><p>'
        chatText += line.text
        chatText += '</p></div>'
    return chatText

问题是,“chatForm”表单没有按预期工作。AddToChat()似乎认为那request.POST.get('theChatText', '')NoneType我尝试提交文本的时候。

所以,是的,我很困惑为什么要这样做。据我所见,'theChatText'应该是 POST 字典中的有效键。

我还要声明我所有的核心游戏逻辑都有效(尽管很明显这不是问题所在)。

任何帮助表示赞赏。

4

1 回答 1

2

原始的jQuery函数:

$(document).ready(function() {
    $('#chatForm').submit(function(e) {
        $.ajax({
            type: 'POST',
            url: "/AddToChat/''' + str(game) + '''/''' + str(player) + '''",
            success: function() {
                $('#chatInput').val("");
            }
        });
        e.preventDefault();
    });
});

data: $(this).serialize(),需要添加,如下所示:

$(document).ready(function() {
    $('#chatForm').submit(function(e) {
        $.ajax({
            type: 'POST',
            url: "/AddToChat/''' + str(game) + '''/''' + str(player) + '''",
            data: $(this).serialize(),
            success: function() {
                $('#chatInput').val("");
            }
        });
        e.preventDefault();
    });
});

否则服务器(或者在这种情况下是 Bottle)将无法读取提交的表单。

于 2012-10-28T09:52:08.713 回答