2.1 项目设计
2.1.1 项目系统设计
menu
:菜单页面playground
:游戏界面settings
:设置界面
对于复杂的界面设计,我们在每个界面下递归细分功能模块,直到实现最基本的功能模块。模块化设计便于项目创建、更新和维护。
project/ #项目系统设计
|-- menu #菜单界面
|-- playground #游戏界面
| |-- maps #地图
| |-- players #人物
| | |-- atcions #人物动作
| | |-- movements #人物移动
| | `-- talents #人物属性
| `-- time #时间
`-- settings #设置界面
2.1.2 项目文件结构
对于一个 Django
项目,有如下框架:
django_project/
|-- django_project #整个Django项目的配置
| |-- __init__.py #初始化文件
| |-- __pycache__
| | |-- __init__.cpython-38.pyc
| | `-- settings.cpython-38.pyc
| |-- asgi.py #异步通信服务启动文件
| |-- settings.py #项目的全局配置文件
| |-- urls.py #项目的全局路由设置
| `-- wsgi.py #web网关服务启动文件
|-- manage.py #命令行工具
`-- project #子应用
|-- __init__.py
|-- admin.py
|-- apps.py
|-- consumers #管理 websocket 函数
|-- migrations
| `-- __init__.py
|-- models #管理数据库数据
|-- static #管理静态文件
| |-- audio #声音
| |-- css #对象格式
| |-- image #图片
| `-- js #对象逻辑(脚本)
|-- templates #管理html
|-- tests.py
|-- urls #管理路由
`-- views #管理http函数
我们在 python
中调用 import urls.xxx
时,需要索引文件 __init__.py
。为了便于维护 urls.py
、views.py
、models.py
,我们将其转为文件夹的方式存储,并在这三个文件夹目录下都添加 __init__.py
文件。
对于 templates
,urls
,views
等的文件夹,最好都建立文件夹menu
,playground
,settings
文件夹,用于细分模块设计。
对于 css
一般不需要细分。
对于 js
需要分为 dist
和 src
两个文件,dist
是最终打包好的 .js
文件,src
用于存储开发时的各种模块化的 .js
文件供。
我们可以在 acappp/
下创建一个文件夹 scripts
,用来存储各种脚本,将 src
打包为 dist
,创建打包 src
的脚本 compress_game_js.sh
如下
#!/bin/bash
JS_PATH=~/workspace/ac_app/ACApp/game/static/js/
JS_PATH_DIST=${JS_PATH}/dist/
JS_PATH_SRC=${JS_PATH}/src/
find ${JS_PATH_SRC} -type f -name "*.js" | sort | xargs cat > ${JS_PATH_DIST}game.js
记得加上可执行权限:
chmod +x compress_game_js.sh
2.1.3 项目全局配置
添加子应用:
打开/game/apps.py
,找到 class GameConfig
,然后在全局的 settings.py
里找到INSTALLED_APPS
,在里面加入 :
'game.apps.GameConfig',
以便将创建的 game
加入进去。
静态文件地址设置:
打开 settings.py
,找到 STATIC_URL = '/static/'
,在该条目上方加入:
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATIC_URL = '/static/'
此外按照上述方式再加入:
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
- 一般来说,
static
存开发的文件,media
存用户的文件。
同时要记得import os
,os.path()
是将路径合并在一起。通过该操作可以使我们的静态文件会放到这个目录下。
import os
from pathlib import Path
2. 2 菜单界面结构创建
2.2.1 html 文件结构
首先进入 /game/templates/
,创建三个文件夹 menu
,playground
,settings
文件夹,便于模块化设计。为了支持多种终端上运行,再创建一个文件夹 multiends
存储 html
文件。
先实现网页端,创建 web.html
:
{% load static %} <!--查找并载入静态文件static的文件夹-->
<head>
<!--<head></head>存放所有的html资源文件-->
<!--引入jQuery的css-->
<link rel="stylesheet" href="https://cdn.acwing.com/static/jquery-ui-dist/jquery-ui.min.css">
<!--引入jQuery的js-->
<script src="https://cdn.acwing.com/static/jquery/js/jquery-3.3.1.min.js"></script>
<!--引入自己写的game.css-->
<link rel="stylesheet" href="{% static 'css/game.css' %}">
<!--引入自己写的game.js-->
<script src="{% static 'js/dist/game.js' %}"></script>
</head>
<body style="margin: 0">
<!--<body></body>以后的网站内容都放在这里面-->
<!--创建游戏框架-->
<div id="ac_game_12345678"></div>
<!--引入js代码,以后前端渲染的部分都在js里面-->
<script>
$(document).ready(function(){
let ac_game = new AcGame("ac_game_12345678");
});
</script>
</body>
js
在客户端渲染,而 views
和 urls
在后端处理,由此实现前后端分离,能够减轻服务器的压力,并能适应多终端的开发需求。
2.2.2 js 对象文件结构
在 html
文件的 <body>
内的 <script>
将页面渲染交给客户,调用 let ac_game = AcGame();
创建一个 js
对象,接下来实现这个创建 js
对象的文件。
进入 /game/static/js/
,同样创建三个文件夹 menu
,playground
,settings
,再创建一个总文件 zbase.js
。由于打包时按照文件名字典序排列的,可以保证在打包的时 zbase.js
在最后打包。
class AcGame {
constructor(id) {
}
}
在 web.html
中的 let ac_game = AcGame()
括号里面添加 id
,即 AcGame("ac_game_12345678")
,表示渲染<div id="ac_game_12345678">
。
2.2.3 views 文件结构
进入 /game/views
,同样创建三个文件夹 menu
,playground
,settings
,在这三个文件夹里存放需要被调用的 .py
文件,故都要添加索引 __init__.py
。
在 /game/views/
里面写总的 index.py
:
from django.shortcuts import render # 从django.shortcuts引入render
def index(request):
return render(request, "multiends/web.html") # 返回响应,渲染"/game/templates/multiends/web.html"
这个 index.py
只会在 html
即 Web
中被调用,未来其他东西都不会调用他它,主要用来访问刚刚写的 html
。
其中 from django.shortcuts import render
是 Django
的渲染工具,render
用来渲染 html
文件,通过 Python
来把 html
的内容写到网页上去。此处的路径是从 /game/templates/
开始的。
2.2.4 urls 文件结构
进入 /game/urls
,同样创建三个文件夹 menu
,playground
,settings
,在这三个文件夹里存放需要被调用的 .py
文件,故都要添加索引 __init__.py
。
每个文件夹下添加对应的路由 index.py
,格式如下:
from django.urls import path
urlpatterns = [
----
]
最后在 /game/urls/
里面写总的 index.py
:
from django.urls import path, include # 引入路径管理
from game.views.index import index # 引入自己写的python
urlpatterns = [
path('', index, name='index'), # 到"/"的路由
path('menu/', include('game.urls.menu.index')), # 到"menu/"的路由
path('playground/', include('game.urls.playground.index')), # 到"playground/"的路由
path('settings/', include('game.urls.settings.index')), # 到"settings/"的路由
]
2.3 菜单界面文件创建
2.3.1 创建 js 对象文件
进入 game/static/js/src/zbase.js
,增添内容为:
class AcGame {
constructor(id) {
this.id = id; //将id存下来
this.$ac_game = $(`#` + id); // 查找#id的html对象
this.menu = new AcGameMenu(this); //创建AcGame的AcGameMenu界面对象
this.playground = new AcGamePlayground(this); //创建AcGame的AcGameMenu界面对象
}
}
以上实现的是整个 js
对象文件的定义部分,接下来在各个模块里实现相应的 js
对象文件。
进入 game/static/js/src/menu
,创建 zbase.js
:
class AcGameMenu {
constructor(root) {
this.root = root; //将信息存下来
this.$menu = $(`
<div class="ac_game_menu">
<div class="ac_game_menu_field">
<div class="ac_game_menu_field_item ac_game_menu_field_item_single_mod">
单人模式
</div>
<br>
<div class="ac_game_menu_field_item ac_game_menu_field_item_multi_mod">
多人模式
</div>
<br>
<div class="ac_game_menu_field_item ac_game_menu_field_item_settings">
设置
</div>
</div>
</div>
`); //创建一个html对象menu
this.root.$ac_game.append(this.$menu); //将html对象加入到这个游戏里面
this.$single_mod = this.$menu.find('.ac_game_menu_field_item_single_mod'); //找到class对应的对象
this.$multi_mod = this.$menu.find('.ac_game_menu_field_item_multi_mod');
this.$settings = this.$menu.find('.ac_game_menu_field_item_settings');
this.start();
}
start() {
this.add_listening_events();
}
add_listening_events() { //监听函数,监听按钮是否被click过
let outer = this;
this.$single_mod.click(function(){ //切换页面的逻辑
outer.hide(); //关闭当前界面
outer.root.playground.show(); //打开playground页面
});
this.$multi_mod.click(function(){
console.log("click mulit_mod");
});
this.$settings.click(function(){
console.log("click settings");
});
}
//api接口函数
show() { //打开界面
this.$menu.show();
}
hide() { //关闭界面
this.$menu.hide();
}
}
jquery
库提供了api
接口append(this.$menu)
,目的是将this.$menu
加入到$ac_game
存储的<div>
块内。<div class="ac_game_menu">
在$menu
内定义一个ac_game_menu
,该样式从/game/static/css/game.css
中调用,其他同理。
同理进入 /game/static/js/src/playground
,创建 zbase.js
:
class AcGamePlayground {
constructor(root) {
this.root = root;
this.$playground = $(`<div>游戏界面</div>`);
this.hide(); //默认先关闭
this.root.$ac_game.append(this.$playground);
this.start();
}
start() {
}
show() { // 打开playground界面
this.$playground.show();
}
hide() { // 关闭playground界面
this.$playground.hide();
}
}
本节重点在于菜单界面的创建,至此简单实现了菜单界面跳转到游戏界面的按钮功能,后续添加实现其他功能。
2.3.2 创建 css 文件
js
对象文件创建完毕后,前端调用会在用户端进行渲染,其 html
样式仍需要从 /game/css
里调用。
首先下载一些静态资源,如背景图片等:
wget --output-document=自定义图片名称 图片地址
进入 /game/static/css/
,打开 game.css
:
/*主菜单界面创建时的css样式*/
.ac_game_menu {
width: 100%;
height: 100%;
background-image: url("/static/image/menu/background.png"); /*背景图片地址*/
background-size: 100% 100%;
user-select: none;
}
/*主菜单的css样式*/
.ac_game_menu_field {
width = 20vw;
position: relative;
top: 40vh;
left: 19vw;
}
/*主菜单条目的css样式*/
.ac_game_menu_field_item {
color: white;
width: 18vw;
height: 7vh;
font-size: 6vh;
font-style: italic;
padding: 2vh;
text-align: center;
background-color: rgba(39, 21, 28, 0.6);
border-radius: 20px;
letter-spacing: 0.5vw;
cursor: pointer;
}
/*hover 控制鼠标悬浮效果*/
.ac_game_menu_field_item:hover {
transform: scale(1.15);
transition: 130ms;
}
2.3.3 打包文件
实现完菜单界面的对应文件后,我们利用之前设计的打包脚本,将这些文件打包到 /game/static/js/dist
。
回到 scripts
文件夹,运行打包脚本:
./compress_game_js.sh
最后启动服务查看菜单界面:
python3 manage.py runserver 0.0.0.0:8000