acwing-Django项目——前期工作+前端js css
创始人
2024-03-30 03:33:40
0

文章目录

  • 1.租服务器配置环境 配置docker环境
    • 创建工作用户ljh并赋予sudo权限
    • 配置免密登录方式
    • 给server1装环境装docker
    • 将AC Terminal中的/var/lib/acwing/docker/images/docker_lesson_1_0.tar镜像上传到租好的服务器中
    • 将镜像加载到本地
    • 配置docker环境
    • 创建项目
    • 配置git
    • 运行一下django
    • Django创建app game
    • 创建自己的页面
    • 我如果把tmux强制关闭,如何再关闭我的server
  • 2.创建菜单界面
    • 项目的系统设计
    • 文件的创建
    • 全局设置
    • 静态文件
    • 创建HTML文件
    • 写views文件
    • 然后写路由
      • 对于路由的理解
      • 到此为止,文件结构就写好了,前期的准备工作完毕了
    • 创建菜单的class
    • 加菜单的选项
    • 如何找bug
  • 3.创建游戏界面
    • 准备工作
    • 创建运动物体的基类
    • 创建地图
    • 创建玩家
    • 创建火球技能
    • 碰撞检测
    • 粒子效果
    • 给所有的敌人随机一个颜色
    • 再加一些效果
  • 4.部署nginx与对接acapp
    • 1. 增加容器的映射端口:80与443
    • 2. 创建AcApp,获取域名、nginx配置文件及https证书
    • 3.修改django项目的配置
    • 配置uwsgi
    • 5.填写信息
    • 6. 使分配的域名生效
    • 7.提交后点”打开应用”按钮,即可预览自己所写的应用


1.租服务器配置环境 配置docker环境

创建工作用户ljh并赋予sudo权限

登录到新服务器。打开AC Terminal,然后

ssh root@xxx.xxx.xxx.xxx  # xxx.xxx.xxx.xxx替换成新服务器的公网IP

创建ljh用户:

adduser ljh  # 创建用户ljh
usermod -aG sudo ljh  # 给用户ljh分配sudo权限

配置免密登录方式

退回AC Terminal,然后配置ljh用户的别名和免密登录
配置别名,进入.ssh/里面
然后vim config

cd /home/acs/.ssh
vim config

vim /etc/ssh/sshd_config进去后如何编辑和保存
然后添加别名

Host server1HostName ip地址User ljh(用户名,一般不写root)

创建秘钥

ssh-keygen

免密登录,一键添加公钥

ssh-copy-id server1

然后就可以便捷的登录到自己的服务器上了

ssh server1

给server1装环境装docker

sudo apt-get update
sudo apt-get install tmux

然后logout
将AC Terminal的配置传到新服务器上:

scp .bashrc .vimrc .tmux.conf server1:

然后进入server1, 可以使用后tmux, 退出tmux, ctrl+d

安装tmux和docker
登录自己的服务器,然后安装tmux:(可省略)

sudo apt-get update
sudo apt-get install tmux

打开tmux。(养成好习惯,所有工作都在tmux里进行,防止意外关闭终端后,工作进度丢失)

然后在tmux中根据docker安装教程安装docker即可。

一般tmux, 快捷键的前缀是Ctrl b, 按完松开之后输 % 可以分栏,但是acwing这个改成了Ctrl a
Ctrl a + % 左右分屏
Ctrl a + “ 上下分屏
Ctrl a + x 结束这块分屏
Ctrl a + o 光标移动
tmux基本用法 tmux基本操作

然后通过tmux装docker,复制官网的命令就行
docker官网
通过docker --version判断是否装好

将AC Terminal中的/var/lib/acwing/docker/images/docker_lesson_1_0.tar镜像上传到租好的服务器中

cd /var/lib/acwing/docker/images/
scp docker_lesson_1_0.tar server1:

然后进入server1

将镜像加载到本地

sudo gpasswd -a ljh docker   #将普通用户username加入到docker组
newgrp docker  #更新docker组

然后就可以自由使用docker命令了

docker load -i django_lesson_1_0.tar  # 将镜像加载到本地
docker images  #查看就会多一个镜像 

创建并运行django_lesson:1.0镜像

docker run -p 20000:22 -p 8000:8000 --name django_server -itd django_lesson:1.0

配置docker环境

进入docker 容器中

docker attach django_server

这也是一个虚拟服务器,我们还是创建一个非根用户

adduser ljh  # 创建用户ljh
usermod -aG sudo ljh  # 给用户ljh分配sudo权限

在容器里我设置的 ljh 的密码是 Ljh

退出容器,不能直接Ctrl+d, 我们要挂起容器

Ctrl+p 再 Ctrl+q

去云平台控制台中修改安全组配置,放行端口20000,ssh登录端口, 8000, django调试端口
管理控制台 - 实例 -更多 -网络与安全组 - 安全组配置 -配置规则, 然后手动添加

然后我们在我们租的服务器里,可以进入docker

ssh ljh@localhost -p 20000

可以进入到这个容器里 然后退出,这个退出 Ctrl + d 就可以了

然后我们退回到acterminal 进入.ssh配置一下别名

cd .ssh/
vim config

然后我配置了一个django, 之后只要ssh django就能进入容器了 密码是 Ljh

Host djangoHostName 120.78.165.208User ljhPort 20000

然后可以配置一下免密登录, 直接 ssh-copy-id django
ssh-copy-id三步实现SSH无密码登录和ssh常用命令
然后就可以从ac terminal 去 ssh django

然后 退回到 acterminal , 把本地这些东西复制到容器里

scp .bashrc .vimrc .tmux.conf django:

这样 我们的docker 环境就配置好了

创建项目

我们进入django, 可以通过 django-admin --version去查看版本号

django-admin startproject acapp

然后我们可以用 ls 看一下多了一个acapp, tree .可以看一下目录结果

配置git

然后cd acapp,在这个目录下 git init , 就会多一个.git文件,这应该是本地git仓库
然后 cd 出来 然后 ssh-keygen,git是通过ssh实现的,所以需要ssh key
然后配置云端的,创建一个仓库来存储 在git.acwing.com创建一个新项目

按照提示,配置一下,Git global setup

git config --global user.name "LIU  JIAHAO"
git config --global user.email "1059723379@qq.com"

再把本地的项目传上去,cd到acapp目录下,然后git add . git commit -m “start project”, 再写一个README.md , vim README.md, 然后把这个readme.md给 git add . git commit -m “add readme”

然后push一下现有的仓库

git remote add origin https://git.acwing.com/LJH2023/acapp.git
git push -u origin --all
git push -u origin --tags

这几行只用写一次,后面就直接git add git commit git push

执行的时候需要输密码, 我们可以cd出来 ,然后cd .ssh/ 然后cat id_rsa.pub, 把公钥复制下来, 然后点击git acwing头像 - 偏好设置 - ssh秘钥 ,把这个复制到上面。
因为git其实就是基于ssh的

然后就能发现项目被传到了git acwing

运行一下django

cd 进入 acapp目录

python3 manage.py runserver 0.0.0.0:8000

然后,在浏览器地址栏,输入自己的ip地址

120.78.165.208:8000

会报错,让You may need to add ‘120.78.165.208’ to ALLOWED_HOSTS.
如果不知道 ALLOWED_HOSTS在哪,可以

ag ALLOWED_HOSTS

他就会全文搜索这个字符串告诉你在哪, 然后cd 进去 , vim settings.py点开,把’120.78.165.208’加进去, 保存 就刷新了, 然后刷新一下网页页面
请添加图片描述
git status一下,会发现,出现了一个__pycache__/的东西,这是python预编译好的东西,我们git维护代码的时候不要维护它
我们cd 回acapp, 仓库的根目录,加一个.gitignore文件

vim .gitignore

然后写 **/pycache 保存
这样就会帮我们过滤掉
然后我们git add . git status, git commit -m " modify allowed", git push
由于我不会复制ac teminal的内容,我每次git push都得输入 账号密码

Django创建app game

python3 manage.py startapp game

然后就会多了一个game 文件夹

然后我们可以 ctrl z退出正在运行的后台

同步一下数据库的修改

python3 manage.py migrate

然后我们再运行python3 manage.py runserver 0.0.0.0:8000
在 120.78.165.208:8000/admin就能进入管理员界面了

我们需要创建一个管理员账号

python3 manage.py createsuperuser 

我创建的用户名是 admin , 密码是Ljh
然后输入就可以登录了

创建自己的页面

cd game
touch urls.py
mkdir templates
ls
接下来整个项目操作的就是 models.py views.py urls.py templates
我们接下来 vim views.py,写一个函数, 每一个页面就是对应这views里的一个函数

from django.http import HttpResponsedef index(request):return HttpResponse(''我的第一个网页")```

写完之后我们 vim urls.py
在这里插入代码,写一个路径,url就是一个路由,告诉要调用哪一个函数

from django.urls import path
from game.views import index
urlpatterns = [path("",  index, name = "index"),
]

我们game app的urls 还需要写到总url 里面, 我们cd 到 acapp/acapp, 打开url

from django.urls import path, include
然后在urlpattern里写一个path
path('game/',  include('game.urls')),

这样的话我们登入 ip地址, /game 就能看见写的view了,如果我们写path(‘’, include(‘game.urls’)), 登入ip直接就是写的view

最后,http://120.78.165.208:8000 是这节课的作品

我买了一个轻量级应用 地址 8.134.129.207:8000

我如果把tmux强制关闭,如何再关闭我的server

首先查看已存在端口号列表:
然后把相应进程的pid 给kill了

  ps aux | grep -i managekill -9 进程的pid

最后我在本地的gitbash创建了别名和免密登录,只要ssh server1 / ssh django

2.创建菜单界面

8.134.129.207:8000

cd acapp然后
python3 manage.py runserver 0.0.0.0:8000

项目的系统设计

在这里插入图片描述

项目系统设计

menu:菜单页面
playground:游戏界面
settings:设置界面

项目文件结构

templates目录:管理html文件
urls目录:管理路由,即链接与函数的对应关系
views目录:管理http函数
models目录:管理数据库数据
static目录:管理静态文件,比如:
-css:对象的格式,比如位置、长宽、颜色、背景、字体大小等
-js:对象的逻辑,比如对象的创建与销毁、事件函数、移动、变色等
-image:图片
-audio:声音

consumers目录:管理websocket函数

文件的创建

rm urls.py views.py models.py 
mkdir urls 和 views 和 models 和 static

要想在不同python文件夹之间import需要在文件夹下面创建__init__.py
分别进入 urls views models 目录下, touch __init__.py

全局设置

时区

在acapp/acapp下 vim settings.py
在108行把时区改成 Asia/Shanghai

在acapp/game中有一个 apps.py 抄到acapp/acapp/settings 中的33行

'game.apps.GameConfig',

静态文件

设置一下静态文件的地址,在settings.py最后121行,先在13行左右import os

再在121行加上 STATIC_ROOT = os.path.join(BASE_DIR, ‘static’)
在125行加上MEDIA_ROOT = os.path.join(BASE_DIR, ‘media’)

static文件就是让本地的文件通过链接来返回的

然后我们进入cd acapp/game/static/image
创建 mkdir menu playground settings

然后我们cd menu

wget --output-document=background.gif 动图的链接

就在静态文件下面的image下面的menu里下载好了
然后在8.134.129.207:8000/static/image/menu/background.gif应该能看到,但是我看不到
以后想放声音的话也可以放在static目录下

然后我们
cd acapp/game/static/css
vim game.css
一个项目的css文件也就这一个了,css文件不用做拆分

然后我们
cd acapp/game/static/js
mkdir dist src
#dist一般存我们最终使用的js文件,src一般存源文件

这个src有很多文件,我们可以写一个脚本把这些合并然后放到src里面
我们cd acapp
mkdir scripts ##### 创建一个文件夹,把项目里用到的脚本放在这里
vim compress_game_js.sh

#! /bin/bash
JS_PATH=/home/ljh/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

给权限~/acapp/scripts$ chmod +x compress_game_js.sh
执行一下~/acapp/scripts$ ./compress_game_js.sh
会发现在:~/acapp/game/static/js/dist 多一个 game.js

创建HTML文件

创建HTML文件还是要创建三个不同的文件夹,因为对应的html文件会很多
cd acapp/game/templates
mkdir menu playground settings

因为以后可以多终端的跑这个游戏
mkdir multiends
cd multiends
vim web.html #web端
前端的工具很多,主流的是vue, 但是这里用了简单的jquery
前端界面是客户端js渲染的,前后端分离,减轻服务器的压力

{% load static %}




cd acapp/game/static/js/src
mkdir menu playground settings
vim zbase.js #排序是字典序,z排在最后
这个是js的构造函数,html文件被返回给前端,前端发现有一个js需要执行,创建一个acgame的class,调用这个构造函数

class AcGame {constructor(id) {}}

写完之后在cd acapp/scrpts 执行./compress_game_js.sh

写views文件

cd acapp/game/views
mkdir menu playground settings
这是一个python 文件夹
所以 在三个文件夹分别 cd…/menu/ 然后touch init.py
然后出来,创建一个总的函数 vim index.py 主要是用来返回我们刚刚用写的html文件的

from django.shortcuts import renderdef index(request):return render(request, "multiends/web.html")

然后写路由

cd acapp/game/urls
mkdir menu playground settings
这是一个python 文件夹
所以 在三个文件夹分别 cd…/menu/ 然后touch init.py
创建总的函数 vim index.py ,把文件夹下的三个文件夹里面的路径include起来的作用

from django.urls import path, includeurlpatterns = [
]  

先去这三个子文件夹里
vim index.py

from django.urls import pathurlpatterns = []

然后回到总文件 cd …

  1 from django.urls import path, include2 from game.views.index import index345 urlpatterns = [6     path("", index, name="index"),7     path("menu/", include("game.urls.menu.index")),8     path("playground/", include("game.urls.playground.index")),9     path("settings/", include("game.urls.settings.index")),10 ]

然后cd acapp/acapp 修改一下全局的路由
vim urls.py

path('', include('game.urls.index')),

对于路由的理解

解释一下,整个Django项目, 访问一个链接,它会优先进到全局的urls里面。进来之后他会去匹配,每一项是用/隔开的,第一个字符串如果是…,就会进入它的路由;比如
path(‘’, include(‘game.urls.index’)), 如果字符串是空的,它就会进入game.urls.index
那么game.urls.index是这样的

from django.urls import path, include
from game.views.index import indexurlpatterns = [path("", index, name="index"),path("menu/", include("game.urls.menu.index")),path("playground/", include("game.urls.playground.index")),path("settings/", include("game.urls.settings.index")),
]

如果下一个还是空的,它会进入index函数,这个函数是game.views.index
那么vies.index是这样的

from django.shortcuts import renderdef index(request):return render(request, "multiends/web.html")

那么这个index函数会去渲染一个html页面,也就是会返回一个字符串,这个内容就是multiends/web.html里面的内容,这个内容就是templates里面的multiends里面的.html
就会返回



到此为止,文件结构就写好了,前期的准备工作完毕了

创建菜单的class

cd acapp/game/static/js/src/menu/
记得js文件改动之后都要执行一下更新合并脚本 cd acapp/scripts 执行 ./compress_game_js.sh
vim zbase.js

  1 class AcGameMenu {                                                   2     constructor(root) {                                             3         	this.root = root                                            4         	this.$menu = $(`                                         5 
6
7 `); 8 this.root.$ac_game.append(this.$menu); 9 } 10 }

设置背景的样式cd acapp/game/static/css, vim game.css

.ac-game-menu {width: 100%;height: 100%; background-image: url("/static/image/menu/background.gif");background-size: 100% 100%; }

设置完之后把这个加到总对象,cd acapp/game/static/js/src/, vim zbase.js

class AcGame {constructor(id) {this.id = id;this.$ac_game = $('#' + id);this.menu = new AcGameMenu(this);}
}

加菜单的选项

cd acapp/game/static/js/src/menu/

class AcGameMenu {constructor(root) {this.root = root;this.$menu = $(`
单人模式

多人模式

退出
`);this.$menu.hide();this.root.$ac_game.append(this.$menu);this.$single_mode = this.$menu.find('.ac-game-menu-field-item-single-mode');this.$multi_mode = this.$menu.find('.ac-game-menu-field-item-multi-mode');this.$settings = this.$menu.find('.ac-game-menu-field-item-settings');this.start();}start() {this.add_listening_events();}add_listening_events() {let outer = this;this.$single_mode.click(function(){outer.hide();outer.root.playground.show("single mode");});this.$multi_mode.click(function(){outer.hide();outer.root.playground.show("multi mode");});this.$settings.click(function(){outer.root.settings.logout_on_remote();});}show() { // 显示menu界面this.$menu.show();}hide() { // 关闭menu界面this.$menu.hide();} }

设置一下框的样式 cd acapp/game/static/css, vim game.css

.ac-game-menu {width: 100%;height: 100%; background-image: url("/static/image/menu/background.gif");background-size: 100% 100%; }
.ac-game-menu-field {width: 20vw; position: relative;top: 40vh;left: 19vw; }.ac-game-menu-field-item {color: white;height: 7vh;width: 18vw;font-size: 6vh;font-style: italic;padding: 2vh;text-align: center;background-color: rgba(39,21,28, 0.6);border-radius: 10px;letter-spacing: 0.5vw;cursor: pointer;}.ac-game-menu-field-item:hover {transform: scale(1.2);transition: 100ms;
}

如何找bug

首先网页地址是 8.134.129.207:8000
cd acapp 运行python3 manage.py runserver 0.0.0.0:8000
按F12 在console里面可以找到报错,可以对着https://git.acwing.com/yxc/acapp 改

3.创建游戏界面

cd acapp/game/templates/multiends vim web.html
改成模块化的引用,作为上节课一个内容的完善

{% load static %}

cd acapp/game/static/js/src

export class AcGame {constructor(id) {this.id = id;this.$ac_game = $('#' + id);this.menu = new AcGameMenu(this);this.playground = new AcGamePlayground(this);this.start();}start() {}
}

记得cd acapp/scripts ./compress_game_js.sh

准备工作

我们这节课要做playground所以方便调试,把js/src里面的zbase.js里面的 this.menu注释掉了
然后cd acapp/game/static/js/src/playground, vim zbase.js

注释掉this.hide,

 1 class AcGamePlayground {2     constructor(root) {3         this.root = root;4         this.$playground = $(`
`);56 // this.hide();7 this.root.$ac_game.append(this.$playground);89 this.start();

打开css文件 cd acapp/game/static/css, vim game.css

37 .ac-game-playground {38     width: 100%;39     height: 100%;40     user-select: none;

cd acapp/game/static/js/src/playground, vim zbase.js
记录一下画布的高宽

 1 class AcGamePlayground {2     constructor(root) {3         this.root = root;4         this.$playground = $(`
`);56 // this.hide();7 this.root.$ac_game.append(this.$playground);8 this.width = this.$playground.width();9 this.height = this.$playground.height();............

创建运动物体的基类

cd acapp/game/static/js/src/playground, mkdir ac_game_object创建一个物体运动的基类
cd ac_game_object, vim zbase.js 创建一个简易的虚拟引擎

  1 let AC_GAME_OBJECTS = [];23 class AcGameObject {4     constructor() {5         AC_GAME_OBJECTS.push(this);67         this.has_called_start = false; //是否执行过start函数8         this.timedelta = 0; //当前帧距离上一帧的时间间隔9     }1011     start() { //只会在第一帧执行一次12     }1314     update() { //每一帧都会执行一次15     }16 ----17     on_destroy() { //被销毁前执行一次18     }1920     destroy() { //删掉该物体21         this.on_destroy();2223         for (let i = 0; i < AC_GAME_OBJECTS.length; i ++) {24             if (AC_GAME_OBJECTS[i] === this) {25                 AC_GAME_OBJECTS.splice(i, 1);26                 break;27             }28         }29     }30 }3132 let last_timestamp;33 let AC_GAME_ANIMATION = function(timestamp) {34     for (let i = 0; i < AC_GAME_OBJECTS.length; i ++) {35         let obj = AC_GAME_OBJECTS[i];36         if (!obj.has_called_start) {37             obj.start();38             obj.has_called_start = true;3940         } else {41             obj.timedelta = timestamp - last_timestamp;42             obj.update();43         }44     }45     last_timestamp = timestamp;4647     requestAnimationFrame(AC_GAME_ANIMATION);4849 }505152 requestAnimationFrame(AC_GAME_ANIMATION); //一秒钟会调用60次

创建地图

cd acapp/game/static/js/src/playground/game_map, mkdir game_map, cd game_map创建一个游戏地图的对象
vim zbase.js

  1 class GameMap extends AcGameObject {2     constructor(playground) {3         super();4         this.playground = playground;5         this.$canvas = $(``);6         this.ctx = this.$canvas[0].getContext('2d');7         this.ctx.canvas.width = this.playground.width;8         this.ctx.canvas.height = this.playground.height;9         this.playground.$playground.append(this.$canvas);101112     }1314     start() {15     }1617     update() { this.render();18     }19 2021     render() {22         this.ctx.fillStyle = "rgba(0, 0, 0)";23         this.ctx.fillRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);24     }25 }

把地图对象放进playground里,cd acapp/game/static/js/src/playground, vim zbase.js

  1 class AcGamePlayground {2     constructor(root) {3         this.root = root;4         this.$playground = $(`
`);56 // this.hide();7 this.root.$ac_game.append(this.$playground);8 this.width = this.$playground.width();9 this.height = this.$playground.height();10 this.game_map = new GameMap(this); //添加进playground按F12才能看见canvas11 this.start();12 }1314 start() {15 }1617 show() { //打开playground界面18 this.$playground.show();19 }2021 hide() { //关闭playground界面22 this.$playground.hide();23 }24}

创建玩家

cd acapp/game/static/js/src/playground, mkdir player
cd player
vim zbase.js

  1 class Player extends AcGameObject {2     constructor (playground, x, y, radius, color, speed, is_me) {3         super();4         this.playground = playground;5         this.ctx = this.playground.game_map.ctx;6         this.x = x;7         this.y = y;8         this.vx = 0;9         this.vy = 0;10         this.move_length = 0;11         this.radius = radius;12         this.color = color;13         this.speed = speed;14         this.is_me = is_me;15         this.eps = 0.1;1617     }1819     start() {20         if (this.is_me) {21             this.add_listening_events();22         }23     }2425     add_listening_events() {26         let outer = this;27         this.playground.game_map.$canvas.on("contextmenu", function(){ //取消右键的菜单28             return false;29         });30         this.playground.game_map.$canvas.mousedown(function(e) { //获取右键点击的坐标31             if (e.which === 3) {32                 outer.move_to(e.clientX, e.clientY);3334             }3536         });37     }3839     get_dist(x1, y1, x2, y2) {40         let dx = x1 - x2;41         let dy = y1 - y2;42         return Math.sqrt(dx * dx + dy * dy);4344     }4546     move_to(tx, ty) {47         this.move_length = this.get_dist(this.x, this.y, tx, ty); //移动的模长48         let angle = Math.atan2(ty - this.y, tx - this.x); //求移动向量的角度49         this.vx = Math.cos(angle); //表示速度,其实是1*cos(angle)50         this.vy = Math.sin(angle);5152     }5354     update() {55         if (this.move_length < this.eps) {56             this.move_length = 0;57             this.vx = this.vy = 0;58         } else {59             let moved = Math.min(this.move_length, this.speed * this.timedelta / 1000); //不能移出界,moved表示的是每秒真实移动的距离60             this.x += this.vx * moved;61             this.y += this.vy * moved;62             this.move_length -= moved;63         }64         this.render();65     }6667     render() {68         this.ctx.beginPath();69         this.ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);70         this.ctx.fillStyle = this.color;71         this.ctx.fill();72     }73 }

当然,玩家这个对象也是会放进playground里,cd acapp/game/static/js/src/playground, vim zbase.js

  1 class AcGamePlayground {2     constructor(root) {3         this.root = root;4         this.$playground = $(`
`);56 // this.hide();7 this.root.$ac_game.append(this.$playground);8 this.width = this.$playground.width();9 this.height = this.$playground.height();10 this.game_map = new GameMap(this);11 this.players = [];12 this.players.push(new Player(this, this.width / 4, this.height / 4, this.height * 0.1, "white", this.height * 0.15, true));13 this.start();14 }1516 start() {17 }1819 show() { //打开playground界面20 this.$playground.show();21 }2223 hide() { //关闭playground界面24 this.$playground.hide();25 }262728 }

创建火球技能

cd acapp/game/static/js/src/playground,
mkdir skill, cd skill
mkdir fireball, cd fireball, vim zbase.js
创建火球类,其实也就是像player一样一个移动的球


然后在player类里实现释放技能的操作,cd acapp/game/static/js/src/playground/player,


然后可以在playground里多加几个敌人

cd acapp/game/static/js/src/playground


然后可以在player里给敌人添加简单的ai,
cd acapp/game/static/js/src/playground/player,


碰撞检测

在fireball里面,cd acapp/game/static/js/src/playground/skill/fireball, vim zbase,js
实现一个is_collision()函数,检测是否发生碰撞,和一个attack()函数,碰撞之后

class FireBall extends AcGameObject {constructor(playground, player, x, y, radius, vx, vy, color, speed, move_length, damage) {super();this.playground = playground;this.player = player;this.ctx = this.playground.game_map.ctx;this.x = x;this.y = y;this.vx = vx;this.vy = vy;this.radius = radius;this.color = color;this.speed = speed;this.move_length = move_length;this.damage = damage;this.eps = 0.1;}start() {}update() {if (this.move_length < this.eps) {this.destroy();return false;}let moved = Math.min(this.move_length, this.speed * this.timedelta / 1000);this.x += this.vx * moved;this.y += this.vy * moved;this.move_length -= moved;for (let i = 0; i < this.playground.players.length; i ++) {let player = this.playground.players[i];if (this.player !== player && this.is_collision(player)) {this.attack(player);}}this.render();}get_dist(x1, y1, x2, y2) {let dx = x1 - x2, dy = y1 - y2;return Math.sqrt(dx * dx + dy * dy);}is_collision(player) {//圆心距离小于等于半径之和就是碰撞let distance = this.get_dist(this.x, this.y, player.x, player.y);if (distance < this.radius + player.radius)return true;return false;}attack(player) {let angle = Math.atan2(player.y - this.y, player.x - this.x);player.is_attacked(angle, this.damage);this.destroy();}render() {this.ctx.beginPath();this.ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);this.ctx.fillStyle = this.color;this.ctx.fill();}}

cd acapp/game/static/js/src/playground/player, 在player里面写一个被击中的函数, vim zbase.js


粒子效果

cd acapp/game/static/js/src/playground,
mkdir particle, cd particle , vim zbase.js

class Particle extends AcGameObject {constructor(playground, x, y, radius, vx, vy, color, speed, move_length) {super();this.playground = playground;this.ctx = this.playground.game_map.ctx;this.x = x;this.y = y;this.radius = radius;this.vx = vx;this.vy = vy;this.color = color;this.speed = speed;this.move_length = move_length;this.friction = 0.9;this.eps = 1;}start() {}update() {if (this.move_length < this.eps || this.speed < this.eps) {//move_length或者速度为0就消失this.destroy();return false;}let moved = Math.min(this.move_length, this.speed * this.timedelta / 1000);this.x += this.vx * moved;this.y += this.vy * moved;this.speed *= this.friction;this.move_length -= moved;this.render();}render() {this.ctx.beginPath();this.ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);this.ctx.fillStyle = this.color;this.ctx.fill();}
}

然后 cd acapp/game/static/js/src/playground/player, 在player里面被击中的函数里,改动效果, vim zbase.js


给所有的敌人随机一个颜色

cd acapp/game/static/js/src/playground,vim zbase.js
在playground里面写一个get_color函数就行

class AcGamePlayground {constructor(root) {this.root = root;this.$playground = $(`
`);// this.hide();this.root.$ac_game.append(this.$playground);this.width = this.$playground.width();this.height = this.$playground.height();this.game_map = new GameMap(this);this.players = [];this.players.push(new Player(this, this.width / 2, this.height / 2, this.height * 0.05, "white", this.height * 0.15, true));for (let i = 0; i < 5; i ++) {this.players.push(new Player(this, this.width / 2, this.height / 2, this.height * 0.05, this.get_random_color(), this.height * 0.15, false));}this.start();}get_random_color() {let colors = ["blue", "orange", "yellow", "pink", "green"];return colors[Math.floor(Math.random() * 5)];}start() {}show() { //打开playground界面this.$playground.show();}hide() { //关闭playground界面this.$playground.hide();}}

再加一些效果

敌人可以发火球去攻击我们,在player下的.js写

class Player extends AcGameObject {constructor (playground, x, y, radius, color, speed, is_me) {super();this.playground = playground;this.ctx = this.playground.game_map.ctx;this.x = x;this.y = y;this.vx = 0;this.vy = 0;this.damage_x = 0;this.damage_y = 0;this.damage_speed = 0;this.move_length = 0;this.radius = radius;this.color = color;this.speed = speed;this.is_me = is_me;this.eps = 0.1;this.friction = 0.9;this.spent_time = 0;this.cur_skill = null;}start() {if (this.is_me) {//如果是自己的话,调用监听事件this.add_listening_events();} else {//如果不是自己let tx = Math.random() * this.playground.width;let ty = Math.random() * this.playground.height;this.move_to(tx, ty);}}add_listening_events() {//监听事件,鼠标点击,按键盘let outer = this;this.playground.game_map.$canvas.on("contextmenu", function(){ //取消右键的菜单return false;});this.playground.game_map.$canvas.mousedown(function(e) { //获取右键点击的坐标if (e.which === 3) {outer.move_to(e.clientX, e.clientY);} else if(e.which === 1) {//点的是鼠标左键的话if (outer.cur_skill === "fireball") {//如果当前技能是火球的话outer.shoot_fireball(e.clientX, e.clientY);//朝tx,ty坐标发火球}outer.cur_skill = null;//左键点完发完火球之后,这个状态清空}});$(window).keydown(function(e) {//获取键盘信息if (e.which === 81) {//百度keycode,js键盘按钮81代表q键outer.cur_skill = "fireball";return false;//代表后续不处理了}});}shoot_fireball(tx, ty) {let x = this.x;let y = this.y;let radius = this.playground.height * 0.01;let angle = Math.atan2(ty - this.y, tx - this.x);let vx = Math.cos(angle), vy = Math.sin(angle);let color = "orange";let speed = this.playground.height * 0.5;let move_length = this.playground.height * 1;new FireBall(this.playground, this, x, y, radius, vx, vy, color, speed, move_length, this.playground.height * 0.01);}get_dist(x1, y1, x2, y2) {let dx = x1 - x2;let dy = y1 - y2;return Math.sqrt(dx * dx + dy * dy);}move_to(tx, ty) {this.move_length = this.get_dist(this.x, this.y, tx, ty); //移动的模长let angle = Math.atan2(ty - this.y, tx - this.x); //求移动向量的角度this.vx = Math.cos(angle); //表示速度,其实是1*cos(angle)this.vy = Math.sin(angle);}is_attacked(angle, damage) {for (let i = 0; i < 10 + Math.random() * 5; i ++) {//被击打之后的粒子效果,随机出现一些粒子let x = this.x, y = this.y;let radius = this.radius * Math.random() * 0.1;let angle = Math.PI * 2 * Math.random();let vx = Math.cos(angle), vy = Math.sin(angle);let color = this.color;let speed = this.speed * 10;let move_length = this.radius * Math.random() * 5;new Particle(this.playground, x, y, radius, vx, vy, color, speed, move_length);}this.radius -= damage;if (this.radius < 10) {this.destroy();return false;}this.damage_x = Math.cos(angle);this.damage_y = Math.sin(angle);this.damage_speed = damage * 100;}update() {this.spent_time += this.timedelta / 1000;if (! this.is_me && this.spent_time > 5 && Math.random() < 1 / 300.0) {let player = this.playground.players[Math.floor(Math.random() * this.playground.players.length)];let tx = player.x + player.speed * this.vx * this.timedelta / 1000 * 0.5;let ty = player.y + player.speed * this.vy * this.timedelta / 1000 * 0.5;this.shoot_fireball(tx, ty);}if (this.damage_speed > 10) {this.vx = this.vy = 0;this.move_length = 0;this.x += this.damage_x * this.damage_speed * this.timedelta / 1000;this.y += this.damage_y * this.damage_speed * this.timedelta / 1000;this.damage_speed *= this.friction;} else {if (this.move_length < this.eps) {this.move_length = 0;this.vx = this.vy = 0;if (!this.is_me) {//对于robots,不能停,循环着随机移动let tx = Math.random() * this.playground.width;let ty = Math.random() * this.playground.height;this.move_to(tx, ty);}} else {let moved = Math.min(this.move_length, this.speed * this.timedelta / 1000); //不能移出界,moved表示的是每秒真实移动的距离this.x += this.vx * moved;this.y += this.vy * moved;this.move_length -= moved;}}this.render();}render() {this.ctx.beginPath();this.ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);this.ctx.fillStyle = this.color;this.ctx.fill();}on_destroy() {for (let i = 0; i < this.playground.players.length; i ++) {if (this.playground.players[i] === this) {this.playground.players.splice(i, 1);}}}}

以上就是这节增加的代码,主要是创建一个player类和fireball类, particle类

4.部署nginx与对接acapp

1. 增加容器的映射端口:80与443

第一步,登录容器,关闭所有运行中的任务。
第二步,登录运行容器的服务器,然后执行:

docker ps             #可以查看容器
docker commit CONTAINER_NAME django_lesson:1.1  # 将容器保存成镜像,将CONTAINER_NAME替换成容器名称
docker images         #可以查看镜像docker stop CONTAINER_NAME      # 关闭容器
docker rm CONTAINER_NAME        # 删除容器# 使用保存的镜像重新创建容器
# 增加了两个端口,80是http的默认,443是https的默认端口, 20000是负责登录的, 8000是负责调试的
docker run -p 20000:22 -p 8000:8000 -p 80:80 -p 443:443 --name django_server -itd django_lesson:1.1

第三步,去云服务器控制台,在安全组配置中开放80和443端口。
我买的阿里云轻量级服务器本身就开放了;这个限制ip来源0.0.0.0/0意思是允许所有ip来访问
在这里插入图片描述
我们用创建的镜像,重新生成容器的时候,公钥以及相关配置文件都不会变,所以我们还是可以直接ssh django进我们的新容器

2. 创建AcApp,获取域名、nginx配置文件及https证书

打开AcWing应用中心,点击“创建应用”的按钮。
在这里插入图片描述
系统分配的域名、nginx配置文件及https证书在如下位置:
在这里插入图片描述
在服务器IP一栏填入自己服务器的ip地址。都是sudo vim, :set paste然后粘上去

将nginx.conf中的内容写入服务器/etc/nginx/nginx.conf文件中。如果django项目路径与配置文件中不同,注意修改路径。
将acapp.key中的内容写入服务器/etc/nginx/cert/acapp.key文件中。
将acapp.pem中的内容写入服务器/etc/nginx/cert/acapp.pem文件中。

然后启动nginx服务:

sudo /etc/init.d/nginx start

3.修改django项目的配置

cd acapp/acapp

打开settings.py文件:
大约在二十七八行左右
将分配的域名添加到ALLOWED_HOSTS列表中。注意只需要添加https://后面的部分。
令DEBUG = False。

归档static文件:
cd acapp,
python3 manage.py collectstatic

然后在acapp就有static文件了

配置uwsgi

在这里插入图片描述
桥梁,效率更高,支持多并发

在django项目中添加uwsgi的配置文件:scripts/uwsgi.ini,内容如下:

cd acapp/scripts, vim uwsgi.ini

[uwsgi]
socket          = 127.0.0.1:8000
chdir           = /home/acs/acapp
wsgi-file       = acapp/wsgi.py
master          = true
processes       = 2
threads         = 5
vacuum          = true

启动uwsgi服务:
cd acapp

uwsgi --ini scripts/uwsgi.ini

5.填写信息

标题:应用的名称
关键字:应用的标签(选填)
css地址:css文件的地址,例如:https://app4189.acapp.acwing.com.cn/static/css/game.css
js地址:js文件的地址:例如:https://app4189.acapp.acwing.com.cn/static/js/dist/game.js
主类名:应用的main class,例如AcGame。
图标:4:3的图片
应用介绍:介绍应用,支持markdown + latex语法。

改动了一些代码的逻辑,比如幕布之类的,以及把js文件的打包脚本加了传给acapp static的语句
下次执行打包要 cd acapp, ./scripts/compress_game_js.sh

6. 使分配的域名生效

填写完服务器IP之后,点“保存”或者“提交”按钮,均可使分配的域名生效。

7.提交后点”打开应用”按钮,即可预览自己所写的应用

等项目调试完之后,可以申请发布应用。审核通过后,你的acapp应用就可以与大家见面啦!

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...
有效的括号 一、题目 给定一个只包括 '(',')','{','}'...
【PdgCntEditor】解... 一、问题背景 大部分的图书对应的PDF,目录中的页码并非PDF中直接索引的页码...