acwing-Django项目——前期工作+前端js css

news2024/12/28 4:32:53

文章目录

  • 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 server1
	HostName 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 django
	HostName 120.78.165.208
	User ljh
	Port 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 HttpResponse

def 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 manage
  kill -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 %}

<head>
<link rel="stylesheet" href="https://cdn.acwing.com/static/jquery-ui-dist/jquery-ui.min.css">
<script src="https://cdn.acwing.com/static/jquery/js/jquery-3.3.1.min.js"></script>
<link rel="stylesheet" href="{% static 'css/game.css' %}">
<script src="{% static 'js/dist/game.js' %}"></script>
</head>

<body style="margin: 0">
	  <div id="ac_game_12345678"></div>
      <script>
          $(document).ready(function(){
              let ac_game = new AcGame("ac_game_12345678"); #一定要new
          });
      </script>
</body>

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 render


def 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, include

urlpatterns = [
]  

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

from django.urls import path


urlpatterns = [

]

然后回到总文件 cd …

  1 from django.urls import path, include
  2 from game.views.index import index
  3
  4
  5 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 index

urlpatterns = [
    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 render

def index(request):
    return render(request, "multiends/web.html")

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


<head>
    <link rel="stylesheet" href="https://cdn.acwing.com/static/jquery-ui-dist/jquery-ui.min.css">
    <script src="https://cdn.acwing.com/static/jquery/js/jquery-3.3.1.min.js"></script>
    <link rel="stylesheet" href="{% static 'css/game.css' %}">
    <script src="{% static 'js/dist/game.js' %}"></script>
</head>

<body style="margin: 0">
    <div id="ac_game_12345678"></div>
    <script>
        $(document).ready(function(){
            let ac_game = AcGame("ac_game_12345678");
        });
    </script>
</body>

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

创建菜单的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 <div class="ac-game-menu">                                          
  6 </div>                                                              
  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 = $(`
<div class="ac-game-menu">
    <div class="ac-game-menu-field">
        <div class="ac-game-menu-field-item ac-game-menu-field-item-single-mode">
            单人模式
        </div>
        <br>
        <div class="ac-game-menu-field-item ac-game-menu-field-item-multi-mode">
            多人模式
        </div>
        <br>
        <div class="ac-game-menu-field-item ac-game-menu-field-item-settings">
            退出
        </div>
    </div>
</div>
`);
        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 %}

<head>
    <link rel="stylesheet" href="https://cdn.acwing.com/static/jquery-ui-dist/jquery-ui.min.css">
    <script src="https://cdn.acwing.com/static/jquery/js/jquery-3.3.1.min.js"></script>
    <link rel="stylesheet" href="{% static 'css/game.css' %}">
</head>

<body style="margin: 0">
    <div id="ac_game_12345678"></div>
    <script type="module">
        import {AcGame} from "{% static 'js/dist/game.js' %}";
        $(document).ready(function(){
            let ac_game = new AcGame("ac_game_12345678");
        });
    </script>
</body>

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 = $(`<div class="ac-game-playground"></div>`);
  5
  6         // this.hide();
  7         this.root.$ac_game.append(this.$playground);
  8
  9         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 = $(`<div class="ac-game-playground"></div>`);
  5
  6         // 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 = [];
  2
  3 class AcGameObject {
  4     constructor() {
  5         AC_GAME_OBJECTS.push(this);
  6
  7         this.has_called_start = false; //是否执行过start函数
  8         this.timedelta = 0; //当前帧距离上一帧的时间间隔
  9     }
 10
 11     start() { //只会在第一帧执行一次
 12     }
 13
 14     update() { //每一帧都会执行一次
 15     }
 16 ----
 17     on_destroy() { //被销毁前执行一次
 18     }
 19
 20     destroy() { //删掉该物体
 21         this.on_destroy();
 22
 23         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 }
 31
 32 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;
 39
 40         } else {
 41             obj.timedelta = timestamp - last_timestamp;
 42             obj.update();
 43         }
 44     }
 45     last_timestamp = timestamp;
 46
 47     requestAnimationFrame(AC_GAME_ANIMATION);
 48
 49 }
 50
 51
 52 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 = $(`<canvas></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);
 10
 11
 12     }
 13
 14     start() {
 15     }
 16
 17     update() { this.render();
 18     }
 19 
 20
 21     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 = $(`<div class="ac-game-playground"></div>`);
  5
  6         // 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才能看见canvas
 11         this.start();
 12     }
 13
 14     start() {
 15     }
 16
 17     show() { //打开playground界面
 18         this.$playground.show();
 19     }
 20
 21     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;
 16
 17     }
 18
 19     start() {
 20         if (this.is_me) {
 21             this.add_listening_events();
 22         }
 23     }
 24
 25     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);
 33
 34             }
 35
 36         });
 37     }
 38
 39     get_dist(x1, y1, x2, y2) {
 40         let dx = x1 - x2;
 41         let dy = y1 - y2;
 42         return Math.sqrt(dx * dx + dy * dy);
 43
 44     }
 45
 46     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);
 51
 52     }
 53
 54     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     }
 66
 67     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 = $(`<div class="ac-game-playground"></div>`);
  5
  6         // 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     }
 15
 16     start() {
 17     }
 18
 19     show() { //打开playground界面
 20         this.$playground.show();
 21     }
 22
 23     hide() { //关闭playground界面
 24         this.$playground.hide();
 25     }
 26
 27
 28 }

创建火球技能

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 = $(`<div class="ac-game-playground"></div>`);

        // 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应用就可以与大家见面啦!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/75782.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++中前置操作性能一定优于后置操作?

后置操作和前置操作&#xff0c;一个会产生临时变量&#xff0c;一个不会产生临时变量&#xff0c;其原因是&#xff1a;前置操作遵循的规则是change-then-use&#xff0c;而后置操作遵循的规则是use-then-change。正因为后置操作的use-then-change原则&#xff0c;使得编译器在…

Python如何pip批量安装指定包 - 最简单方法

文章目录背景解决办法1. 制作requirements.txt文件2. 将requirements.txt传到需要部署的电脑上3. 批量安装包背景 有很多台服务器需要配置, 简单说也就是公司给我配备了3台Windows, 我需要配置Python环境并安装7个包, 如果按照常规的pip install我至少得安装3x721次, 并且得一…

data shift--学习笔记

一般假设训练集和测试集是独立同分布的&#xff0c;才能保证在训练集上表现良好的模型同样适用于测试集。当训练集和测试集不同分布时&#xff0c;就发生了dataset shiftdata shift类型&#xff1a; 协变量偏移&#xff08;covariate shift&#xff09;&#xff1a; 协变量&…

简约而不简单!分布式锁入门级实现主动续期-自省

一、背景 一个分布式锁应具备的功能特点中有避免死锁这一条&#xff1a; 如果某个客户端获得锁之后处理时间超过最大约定时间&#xff0c;或者持锁期间内发生了故障导致无法主动释放锁&#xff0c;其持有的锁也能够被其他机制正确释放&#xff0c;并保证后续其它客户端也能加锁…

Unity 3D 刚体(Rigidbody)|| Unity 3D 刚体实践案例

Unity 3D 中的 Rigidbody 可以为游戏对象赋予物理特性&#xff0c;使游戏对象在物理系统的控制下接受推力与扭力&#xff0c;从而实现现实世界中的物理学现象。 我们通常把在外力作用下&#xff0c;物体的形状和大小&#xff08;尺寸&#xff09;保持不变&#xff0c;而且内部…

Vue3 —— Pinia 的学习指南以及案例分享

文章目录 前言一、什么是pinia?二、为什么要使用Pinia?三、Pinia对比Vuex四、具体使用方法 1.安装2.创建一个store五、state 1.访问state2.重置状态3.修改state4.批量修改state5.替换state六、getters 1.访问getters2.getters传参3.写为普通函数可调用this4.访问其他的store中…

可见光热红外图像融合算法设计

本设计方式中对于多源图像融合算法采用以下三个步骤进行&#xff1a; 多源图像目标特征提取&#xff1b;多源图像配准&#xff1b;多源图像融合。 1&#xff0e;多源图像目标特征提取 多源图像的目标特征提取中&#xff0c;优先对目标图像进行预处理&#xff0c;对于可见光图像…

品牌势能铸就非凡经典,凯里亚德与郁锦香酒店亮相品牌沙龙会烟台站

近日&#xff0c;汇聚国内众多投资人的锦江酒店(中国区)品牌沙龙会烟台站顺利举行。本次沙龙活动以“齐风鲁韵 锦绘未来”为主题&#xff0c;锦江酒店(中国区)旗下众多优秀品牌共同亮相。凯里亚德酒店与郁锦香酒店在本次活动中向投资人展示了在如今复杂多变的酒店市场中如何以强…

Java面向对象:继承

面向对象三大特征之二&#xff1a;继承 目录 面向对象三大特征之二&#xff1a;继承 1.继承是什么&#xff1a; 2.继承的好处 继承概述的总结 1.什么是继承&#xff1f;继承有什么好处&#xff1f; 2.继承的格式是什么样的&#xff1f; 3.继承后子类的特点是什么&#x…

Docker介绍及项目部署

安装Docker 关闭SELINUX服务 SELINUX是CentOS系统捆绑的安全服务程序&#xff0c;因为安全策略过于严格&#xff0c;所以建议搭建关闭这项服务 修改/etc/selinux/config文件&#xff0c;设置SELINUXdisabled vim /etc/selinux/config # 设置SELINUXdisabled# 设置完成后重启…

[附源码]计算机毕业设计姜太公渔具销售系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Crane如何做到利用率提升3倍稳定性还不受损?

作为云平台用户&#xff0c;我们都希望购买的服务器物尽其用&#xff0c;能够达到最大利用率。然而要达到理论上的节点负载目标是很的&#xff0c;计算节点总是存在一些装箱碎片和低负载导致的闲置资源。下图展示了某个生产系统的CPU资源现状&#xff0c;从图中可以看出&#x…

编译器设计(十二)——指令选择

文章目录一、简介二、代码生成三、扩展简单的树遍历方案四、通过树模式匹配进行指令选择4.1 重写规则4.2 找到平铺方案五、通过窥孔优化进行指令选择5.1 窥孔优化5.2 窥孔变换程序六、高级主题6.1 学习窥孔模式6.2 生成指令序列七、小结和展望一、简介 指令选择&#xff08;in…

java面试题-并发

1. 并行和并发有什么区别&#xff1f; 并行&#xff1a;多个处理器或多核处理器同时处理多个任务。并发&#xff1a;多个任务在同一个 CPU 核上&#xff0c;按细分的时间片轮流(交替)执行&#xff0c;从逻辑上来看那些任务是同时执行。 如下图&#xff1a; 并发 两个队列和一…

从功能测试到自动化测试,待遇翻倍,我整理的超有用工作经验分享~

我想应该有很多测试人员应该有这样的疑虑&#xff0c;自动化测试要怎么去做&#xff0c;现在我把自己的一些学习经验分享给大家&#xff0c;希望对你们有帮助&#xff0c;有说的不好的地方&#xff0c;还请多多指教&#xff01; 对于测试人员来说&#xff0c;不管进行功能测试还…

从股票市场选择配对的股票:理论联系实际

我们有了计算距离的方法&#xff0c;即共同因子相关系数的绝对值就是衡量协整性的一个好方法。现在看一些实际应用中会遇到的问题。 整合的特定回报的平稳性&#xff08;Stationarity of Integration Specific Returns) 两个时间序列协整的必要条件是整合的特定回报时序是平稳…

k8s安装3节点集群Fate v1.7.2

采用k8s&#xff0c;而非minikube, 在3个centos系统的节点上安装fate集群。 集群配置信息 3节点配置信息如下图&#xff1a; 当时kubefate最新版是1.9.0&#xff0c;依赖的k8s和ingress-ngnix版本如下&#xff1a; Recommended version of dependent software: Kubernetes:…

Java编码的坑你知多少?

货币计算坑&#xff1a; 这段代码你认为结果是多少&#xff1f; 我们期望的结果是0.4&#xff0c;也应该是这个数字&#xff0c;但是打印出来的却是0.40000000000000036&#xff0c;这是为什么呢&#xff1f; 这是因为在计算机中浮点数有可能&#xff08;注意是可能&#xff0…

Flask从入门到放弃(介绍、模版语法案例、配置文件、路由本质、CBV整体流程)

文章目录一、Flask介绍二、Flask快速使用三、Flask展示用户信息案例四、Flask配置文件五、路由系统1&#xff09;路由系统2&#xff09;路由本质3&#xff09;Add_url_rule的参数六、Flask的CBV1&#xff09;CBV的写法2&#xff09;CBV添加装饰器3&#xff09;as_view的执行流程…

排名前十的仓库管理系统大盘点(真实测评)!

通过本篇文章&#xff0c;您将了解以下问题&#xff1a;1、国内适合企业的仓库管理系统软件有哪些&#xff0c;排名怎么样&#xff1f;2、企业在选择仓库管理系统时应考虑哪些因素&#xff1f; 目前市场上有多种仓库管理系统&#xff0c;不同的仓库管理系统由于目标市场的不同…