登录到新服务器。打开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
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判断是否装好
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 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 .可以看一下目录结果
然后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
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都得输入 账号密码
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
首先查看已存在端口号列表:
然后把相应进程的pid 给kill了
ps aux | grep -i managekill -9 进程的pid
最后我在本地的gitbash创建了别名和免密登录,只要ssh server1 / ssh django
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文件会很多
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
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
就会返回
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;
}
首先网页地址是 8.134.129.207:8000
cd acapp 运行python3 manage.py runserver 0.0.0.0:8000
按F12 在console里面可以找到报错,可以对着https://git.acwing.com/yxc/acapp 改
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类
第一步,登录容器,关闭所有运行中的任务。
第二步,登录运行容器的服务器,然后执行:
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进我们的新容器
打开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
cd acapp/acapp
打开settings.py文件:
大约在二十七八行左右
将分配的域名添加到ALLOWED_HOSTS列表中。注意只需要添加https://后面的部分。
令DEBUG = False。
归档static文件:
cd acapp,
python3 manage.py collectstatic
然后在acapp就有static文件了
桥梁,效率更高,支持多并发
在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
标题:应用的名称
关键字:应用的标签(选填)
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
填写完服务器IP之后,点“保存”或者“提交”按钮,均可使分配的域名生效。
等项目调试完之后,可以申请发布应用。审核通过后,你的acapp应用就可以与大家见面啦!
下一篇:【C语言】解题训练