好家伙,天天拖,终于写完了
代码已开源(Gitee)
PH-planewar: 个人开发的全栈小游戏 前端:vue2 + element-ui 后端: Springboot + mybatis-plus 数据库: mysql 目前实现功能: 1.注册登陆 2.游戏数据保存 3.游戏运行 (gitee.com)
(前后端放一起了)
怎么说呢,感觉比较简洁,但是问题不大
实现了分数保存的功能
1.刷新页面后依旧保存数据
2.重新登录后,依旧保存数据
3.生命值为零后,游戏重置
Game.vue
MyLogin.vue
<template>
<div class="login-container">
<div class="login-box">
<!-- 头像区域 -->
<div class="text-center avatar-box">
<img src="../assets/logo.png" class="img-thumbnail avatar" alt="">
</div>
<!-- 表单区域 -->
<div class="form-login p-4">
<!-- 登录名称 -->
<div class="form-group form-inline">
<label for="username">账号:</label>
<input type="text" class="form-control ml-2" id="username" placeholder="请输入账号" autocomplete="off"
v-model.trim="loginForm.loginName" />
</div>
<!-- 登录密码 -->
<div class="form-group form-inline">
<label for="password">密码:</label>
<input type="password" class="form-control ml-2" id="password" placeholder="请输入密码"
v-model.trim="loginForm.password" />
</div>
<!-- 登录和重置按钮 -->
<div class="form-group form-inline d-flex justify-content-end">
<button type="button" class="btn btn-secondary mr-2" @click="writenum">测试</button>
<button type="button" class="btn btn-secondary mr-2" @click="toregister">去注册</button>
<button type="button" class="btn btn-primary" @click="login">登录</button>
</div>
</div>
</div>
</div>
</template>
<script>
import bus from '../js/eventBus'
export default {
name: 'MyLogin',
data() {
return {
loginForm: {
id: '',
password: '',
life: null,
score: null,
loginName: null,
isFirst:true
}
}
},
methods: {
writenum() {
this.loginForm.loginName = 123456;
this.loginForm.password = 123456;
},
login() {
// console.log(this.$store.state.count)
// console.log('submit!',this.loginForm);
//表单验证
if (this.loginForm.loginName == "") {
this.$message({
message: '请输入用户名',
type: 'error'
});
return;
}
if (this.loginForm.password == "") {
this.$message({
message: '请输入密码',
type: 'error'
});
return;
}
//发送登陆请求
if (this.loginForm.loginName != "" && this.loginForm.password != "") {
this.axios.post('http://localhost:3312/sys-user/login', this.loginForm).then((resp) => {
console.log("this is login", resp);
let data = resp.data;
// console.log(this.$store.state.user)
console.log(resp.data.content)
//es6语法,扩展操作符,找到resp.data.content的每一个属性然后赋值给新的对象
// this.$store.state.user = { ...resp.data.content }
// console.log(this.$store.state.user)
//localStorage存
localStorage.setItem("insuranceCode", JSON.stringify(resp.data.content));
console.log(this.loginForm.isFirst)
localStorage.setItem("getisFirst", JSON.stringify(this.loginForm.isFirst));
console.log(JSON.parse(localStorage.getItem("getisFirst")))
//localStorage取
console.log(JSON.parse(localStorage.getItem("insuranceCode")))
if (data.success) {
this.loginForm = {};
this.$message({
message: '登陆成功!!!',
type: 'success'
});
this.$router.push({ path: '/game' })
} else {
this.$message({
message: '登陆失败,密码错误或用户名未注册',
type: 'error'
});
console.log(data)
}
})
}
},
toregister() {
this.$router.push('/register')
},
},
mounted() {
// bus.$emit('getLoginName', this.loginForm)
}
}
</script>
<style lang="less" scoped>
.login-container {
background-color: #35495e;
height: 100%;
.login-box {
width: 400px;
height: 250px;
background-color: #fff;
border-radius: 3px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
box-shadow: 0 0 6px rgba(255, 255, 255, 0.5);
.form-login {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
box-sizing: border-box;
}
}
}
.form-control {
flex: 1;
}
.avatar-box {
position: absolute;
width: 100%;
top: -65px;
left: 0;
.avatar {
width: 120px;
height: 120px;
border-radius: 50% !important;
box-shadow: 0 0 6px #efefef;
}
}
</style>
这个怎么说呢,其实整个思路非常简单,就是写的时候会有很多小毛病,小bug
思路:
首先我们在登陆的时候,拿着用户输入的用户名和密码,发一次登陆请求,
后端验证密码后,将用户的数据返回(包括id,分数,生命...)
前端拿到数据之后,将数据保存到本地localStorage
localStorage.setItem("insuranceCode", JSON.stringify(resp.data.content));
我们在表单数据中添加一个isFirst属性,来判断是否首次进入游戏界面
isFirst:true
localStorage.setItem("getisFirst", JSON.stringify(this.loginForm.isFirst));
if (JSON.parse(localStorage.getItem("getisFirst")) == true) {
location.reload();
console.log("已刷新")
localStorage.setItem("getisFirst", JSON.stringify("false"));
}
将页面刷新
随后将isFirst的状态改为"false"
(解释一下,感觉是资源加载的问题,首次进入游戏界面的时候,需要刷新一下,图片资源才能加载出来,
这也是为什么没有用其他的传值方案.其他的传值方案,刷新一下就没了)
//ES6对象的拓展运算符{...Object}
//拓展运算符(...)用于取出参数对象所有可遍历属性然后拷贝到当前对象
this.player = { ...JSON.parse(localStorage.getItem("insuranceCode")) };
window.life = this.player.life
window.score = this.player.score
window.life和window.score是我们的游戏参数
随后就是我们的关键计时器了
setInterval(() => {
//当生命值小于1,即为零时,游戏重置
if (window.life < 1) {
// window.life = 3
// window.score = 0;
console.log("已重置")
this.player.life = 3;
this.player.score = 0;
localStorage.setItem("insuranceCode", JSON.stringify(this.player));
this.axios.post('http://localhost:3312/sys-user/update', this.player)
.then((resp) => {
console.log("this is update", resp);
let data = resp.data;
//
if (data.success) {
console.log({
message: '修改成功',
type: 'success'
});
}
})
window.life = 3
window.score = 0
}
this.player.life = window.life
this.player.score = window.score
console.log(this.player)
localStorage.setItem("insuranceCode", JSON.stringify(this.player));
console.log(this.player.life, this.player.score,window.life,window.score)
this.axios.post('http://localhost:3312/sys-user/update', this.player)
.then((resp) => {
console.log("this is update", resp);
let data = resp.data;
//
if (data.success) {
console.log({
message: '修改成功',
type: 'success'
});
}
})
}, 1000)
这里是一个每秒(1000毫秒)执行一次的计时器
此处进行判断,
随后发一次请求,保存数据
this.player.life = window.life
this.player.score = window.score
更新分数和生命值,然后发请求,将数据保存
解释完毕
常见触发错误的情况如果传入的字段多了会自动过滤如果传入的少了会报错,必填字段如果传入的字段名称对不上也会报错如果传入的类型不对会自动转换,如果不能转换则会报错错误的触发pydantic会在它正在验证的数据中发现错误时引发ValidationError注意验证代码不应该抛出ValidationError本身而是应该抛出ValueError、TypeError、AssertionError或他们的子类ValidationError会包含所有错误及其发生方式的信息访问错误的方式e.errors():返回输入数据中发现的错误的列表e.json():以JSON格式返回错误(推荐)str(e):以人类可读的方式返回错误简单栗子#一定要导入ValidationError frompydanticimportBaseModel,ValidationError classPerson(BaseModel): id:int name:str try: #id是个int类型,如果不是int或者不能转换int会报错 p=Person(id="ss",name="halle
PsychoPyRose小哥是个代码狂,个人喜欢编写代码来实现相关实验设计,因为编写代码来实现实验十分灵活。PsychoPy安装与测试案例PsychoPy文字刺激、图片刺激和光栅刺激 这篇主要介绍视频刺激、音频刺激。视频刺激1.打开Coder视图2.如下图在Coder编辑器中,编写代码。#-*-coding:utf-8-*- ''' 视频刺激 ''' #导入工具 frompsychopyimportvisual,core,event """ 用visual.Window创建一个窗口/屏幕来创建想要呈现文字/图片等这些刺激。 visual.Window的参数解析: size:屏幕分辨率的大小,size=(600,400) color:表示屏幕颜色。(0,0,0)是RGB模式,取值范围是[-1,1],全为-1的话是纯黑色,全为1是白色。 当然也可以采用其他方式设置颜色,比如直接用颜色名:color='green'。 fullscr:True为全屏,默认值为False不全屏。
【RabbitMQ服务器】 # 在 vhosttest 里面有 exchangetest 和 queuetest 通过 rkeytest 绑定 Broker: 192.168.0.xx virtual host: vhosttest Exchange: exchangetest Queue: queuetest Routing key: rkeytest复制【Python环境】OS: Windows 10 Python: 3.6.3 x64 pika: 0.11.2复制【查看队列状态】# 通过浏览器查看队列状态 http://192.168.0.xx:15672/api/queues/vhosttest/queuetest # 通过命令行查看队列状态 curl -u user:password http://192.168.0.xx:15672/api/queues/vhosttest/queuetest | jq # 通过命令行查看队列长度(messages = messages_ready + messages_unacknowledged) curl -s -u u
准备两台服务器,假设IP地址为172.31.27.67主服务器172.31.27.69从服务器因为我用的镜像是docker.io/cytopia/mysql-8.0,所以我们需要先把该镜像给pull下来。dockerpulldocker.io/cytopia/mysql-8.0在/home下建一个文件夹mkdir/home/wen在主服务器建一个master.my.cnf内容如下[client] socket=/var/sock/mysqld/mysqld.sock [mysql] socket=/var/sock/mysqld/mysqld.sock [mysqld] skip-host-cache skip-name-resolve datadir=/var/lib/mysql user=mysql port=3306 bind-address=0.0.0.0 socket=/var/sock/mysqld/mysqld.sock pid-file=/var/run/mysqld/mysqld.pid general_log_file=/var/log/mysql/query.lo
用NumPy手写所有主流ML模型,普林斯顿博士后DavidBourgin最近开源了一个非常剽悍的项目。超过3万行代码、30多个模型,这也许能打造「最强」的机器学习基石?NumPy作为Python生态中最受欢迎的科学计算包,很多读者已经非常熟悉它了。它为Python提供高效率的多维数组计算,并提供了一系列高等数学函数,我们可以快速搭建模型的整个计算流程。毫不负责任地说,NumPy就是现代深度学习框架的「爸爸」。 尽管目前使用NumPy写模型已经不是主流,但这种方式依然不失为是理解底层架构和深度学习原理的好方法。最近,来自普林斯顿的一位博士后将NumPy实现的所有机器学习模型全部开源,并提供了相应的论文和一些实现的测试效果。项目地址:https://github.com/ddbourgin/numpy-ml根据机器之心的粗略估计,该项目大约有30个主要机器学习模型,此外还有15个用于预处理和计算的小工具,全部.py文件数量有62个之多。平均每个模型的代码行数在500行以上,在神经网络模型的layer.py文件中,代码行数接近4000。这,应该是目前用NumPy手写机器学习模型的「最高境界」
最近官网改版的任务交给了我,开发使用的是jq操作dom,后台php渲染的方式,如今已经开发完成,现在把一些问题记录下来,已备忘。1、Safari浏览器不能自动播放视频这次官网首页是有一个内嵌视频,正常情况下给video标签加上autoplay属性就能加载完自动播放了,但是实际发现Safari不会,查询了解到新版Safari禁用了自动播放,解决办法就是手动写行代码video.play();就解决了。2、移动端浏览器对video标签兼容不好在查看移动端效果的时候,发现多个浏览器对video标签做了自动置顶,也就是跳出正常布局,显示在页面最顶层,而且就算不置顶,当点击播放以后也会跳出布局,后来我在网上查了很多资料,也想了很多办法,由于我用的原生的video标签,所以考虑使用video.js等几个有名的第三方库试试,结果并不令人满意,这些库在pc端很完美,但是移动端并不理想,而我苦苦寻找没有发现有效的解决办法,最后和UI商量用gif代替了mp4。3、首页视频加载慢的优化方案在pc端,由于视频有4M,加载完成之前,视频区域会产生空白,移动端gif也很大,也有同样问题,于是选择在页面开始加载占位图
ABAP透明表里的时间戳,数据类型为dec:有个需求:计算这两个时间戳之间的天数间隔,丢弃时间戳年-月-日8位后面的小时:分钟:秒。举个例子:如果时间戳是20180918173132,丢弃173132,只保留20180918,然后再计算天数间隔。直接用CDSview的字符串操作函数substring是不行的,因为时间戳类型dec和substring期待的字符串类型不匹配。解决方案:先将时间戳字段类型从dec强制转换成abap.dats:@AbapCatalog.sqlViewName:'zproday' @AbapCatalog.compiler.compareFilter:true @AccessControl.authorizationCheck:#CHECK @EndUserText.label:'Daybetween' defineviewzdate_day_betweenasselectfromcomm_product{ keycomm_product.product_idasprod_id, comm_product.pr
我们知道已经有很多像Awtstat这样的使用perl、c或者c++开发的强大的日志分析工具,但是同样也有很多使用PHP开发并且开源的日志分析软件,今天我就收集了一些与大家分享。1、LogAnalyzerLogAnalyzer是Adiscon的监控软件产品线中的一部分。可以再Windows以及Unix环境下运行。LogAnalyzer本是是免费的,GPL许可的产品。LogAnalyzer的原名为phpLogCon,他在2010年的3月29日发布了3.0的稳定版,并且正式改名为LogAnalyzer。程序运行必须有他们制定的数据支持,在Windows环境下,可以使用MonitorWareAgent、WinSysLog、EventReport。在Linux环境下可以使用rsyslog。现在Yum的源中包含了rsyslog这款软件,源中的版本是3.22.1,官方的最高版本是4.6.4的稳定版以及6.1.0的开发版。由于不能使用原生的数据进行分析,我觉得算是他的一个缺点。2、Jawstats这是一款基于Awstat的PHP开源程序,提供了非常漂亮的分析统计结果的展示界面,支持中文。他的作者是Jo
在保密你的服务器和数据,防备当前复杂的攻击,SQLServer有你需要的一切。但在你能有效使用这些安全功能前,你需要理解你面对的威胁和一些基本的安全概念。这篇文章提供了基础,因此你可以对SQLServer里的安全功能充分利用,不用在面对特定威胁,不能保护你数据的功能上浪费时间。身份验证是验证主体(需要访问SQLServer数据库的用户或进程,是声称是的人或物)的过程。主体需要唯一的身份,这样的话SQLServer可以决定主体有哪个许可。在提供安全访问数据库对象中,正确的身份验证是必须的第一步。SQLServer支持身份验证的两个途径:Windows集成身份验证和SQLServer身份验证。你使用的途径取决于网络环境,应用程序访问数据库的类型和这些应用程序的用户类型。Windows身份验证:这个身份验证方式依赖于Windows来担当重任——当用户登录到Windows是验证身份。访问SQLServer对象的许可然后会分配给Windows登录。只有当SQLServer运行在支持WindowsNT或Kerberos身份验证的Windows版本上才可以使用,这个自Windows2000起已经几乎
HTTP为什么会出现HTTP协议,从HTTP1.0到HTTP3经历了什么?HTTPS又是怎么回事?HTTP是一种用于获取类似于HTML这样的资源的应用层通信协议,他是万维网的基础,是一种CS架构的协议,通常来说,HTTP协议一般由浏览器等“客户端”发起,发起的这个请求被称为Request,服务端接受到客户端的请求后,会返回给客户端所请求的资源,这一过程被称为Response,在大部分情况下,客户端和服务器之间还可能存在许多proxies,他们的作用可能各不相同,有些可能作为网关存在,有些可能作为缓存存在。HTTP协议有三个基本的特性:简单:HTTP的协议和报文是简单,易于理解和阅读的(HTTP/2已经改用二进制传输数据,但HTTP整体还是简单的)可拓展的:请求和响应都包括“Header”和“Body”两部分,我们可以通过添加头部字段轻松的拓展HTTP的功能无状态的:服务端不保存客户端状态,也就是说每一次请求的服务端来说都是唯一无差别的,我们只能通过Cookie等技术创建有状态的会话。HTTP的历史HTTP的历史可以追溯到万维网刚被发明的时候,1989年,TimBerners-Lee博士
设计模式 静态工厂方法 介绍 什么是静态工厂方法 通过类内部的静态方法创建对象而非new publicstaticvoidmain(String[]args){ Calendardate=Calendar.getInstance(); Integera=Integer.valueOf(4); } //可以看到通过Calendar的静态方法getInstance()就获得了一个Calendar对象 复制 透过现象看本质 查看源码 //以较为简单的Integer为例 publicstaticIntegervalueOf(inti){ if(i>=IntegerCache.low&&i<=IntegerCache.high) returnIntegerCache.cache[i+(-IntegerCache.low)]; returnnewInteger(i); } publicInteger(intvalue){ this.value=value; } 复制 可以看到调用了valueOf方法实际上还是使用了构造方法来进行实现 优
原理 这个shader姑且是根据自己的理解写的,如果有什么不对的评论区提醒一下咯,一般来说模糊和边缘检测这种效果是用卷积来实现的,可以通过使用不同的卷积核来获得图像的特征,模糊其实就是将计算的像素附近的像素乘上一定的权重加起来实现的效果,要保证这些权重的合为1,所以在计算出每个位置的权重后还要除以他们的平均值,用高斯函数的目的就是获得一个合理的权重,根据二维高斯函数的公式 可以把x^2+y^2视为采样像素到中心像素的距离,所以代公式很容易可以得到二维高斯函数的值。 Shader"Hidden/Blurry" { Properties { _MainTex("Base(RGB)",2D)="white"{} _Sigma("Sigma",Range(1.0,5.0))=1.5 _BlurRadius("BlurRadius",Range(1.0,5.0))=3.0 } CGINCLUDE #include"UnityCG.cginc" structv2f_blur { float4pos:SV_POSITION;//顶点位置 float2uv:TEX
题目描述 在一个地图上有N个地窖(N<=200),每个地窖中埋有一定数量的地雷。同时,给出地窖之间的连接路径,并规定路径都是单向的,也不存在可以从一个地窖出发经过若干地窖后又回到原来地窖的路径。某人可以从任一处开始挖地雷,然后沿着指出的连接往下挖(仅能选择一条路径),当无连接时挖地雷工作结束。设计一个挖地雷的方案,使他能挖到最多的地雷。 输入 第一行一个整数n表示有n个地窖 第二行有n个整数表示每个地窖的地雷数 以下有若干行,每行有两个数x,y表示x可以到y,保证x小于y。 最后一行有两个0,表示输入结束 输出 第一行输出挖地雷的顺序。 第二行为最多挖出的地雷数 样例输入 6 51020545 12 14 24 34 45 46 56 00复制 样例输出 3-4-5-6 34复制 #include<bits/stdc++.h> usingnamespacestd; inta[201],a
一、全景图像拼接步骤 1、使用SIFT算法寻找关键特征点 2、建立BFMatcher匹配器将图片特征点进行匹配 3、特征点多于4个则可以计算视角变换矩阵 4、将图片经过变换矩阵变换 5、图片变换过后进行拼接 二、参考代码 importnumpyasnp importcv2 classStitcher: #拼接函数 defstitch(self,images,ratio=0.75,reprojThresh=4.0,showMatches=False): #获取输入图片 (imageB,imageA)=images #检测A、B图片的SIFT关键特征点,并计算特征描述子 (kpsA,featuresA)=self.detectAndDescribe(imageA) (kpsB,featuresB)=self.detectAndDescribe(imageB) #匹配两张图片的所有特征点,返回匹配结果 M=self.matchKeypoints(kpsA,kpsB,featuresA,featuresB,ratio,reprojThresh) #如果返回结果为空,没有匹配成功的特征点,退
LR12中web_js_runAPI非常坑,只能调用一个JS文件;更坑的是,不能通用一个JS调用另外一个JS;(可能有,但在网上找了N个国家,都没有找到!如有,还请朋友告之,谢谢。) 现大部分的前端登录都有使用到RSA加密,以保障用户在登录的时候,账号密码不直接以明文方式传输,经过加密的账号密码即使被截取,也难以破解出真实的账号密码;RSA相关信息请自行搜索了解或下载,RSA加密算法在网上有N多开源的现成库可用(前、后端库); 经RSA加密的登录流程大致为: 1、前端在登录时会向服务端请求RSA四个关键值:PublicKey,Exponent,rKey,Modulus;2、前端使用获取到的Exponent,Modulus(通过RSA库在前端执行)计算出私钥,然后使用获得的公钥以及私钥对用户的账号密码进行加密,并生成加密后的字符串;3、最后前端将完成加密的字符串发送给服务端,服务端解密成功后,返回登录成功的状态;以下将以RSA加密登录为例,演示在Loadrunner中的如何实现; 1Action() 2{ 3//charcliEncrypt[1000];//用于保存需要加密的拼接好的字
updateon21.12.30:添加了polyeva;修补了polymod处多测时可能产生的bug。 updateon22.2.7:重写(前一版太丑了),改为完全封装版本(使用std::vector<int>存放多项式系数,运算在命名空间polynomial::里) updateon22.2.11第二版增加了快速求值插值(但是使用的是利用多项式取模进行降次的做法,常数巨大,关于转置原理的做法见作者在Luogu5050的提交记录), 实现的并不优秀,但应该很稳(雾)。全部提交测试过,部分由Vincra这个账号提交。 索引: Ver2(施工中) 使用polyA;来声明一个名为\(A\)的多项式,其原型为vector<int>a;,较Ver1更为优美、精简,去掉了没啥用、并且很丑的常数项不为\(1\)时的多项式快速幂。 下面是P5158的代码: constintdjq=998244353; inlineintksm(intbase,intp){ intret=1; while(p){ if(p&1)ret=1ll*ret*base%djq; b
#include<iostream> #include<cstdlib> #include<algorithm> #include<vector> usingnamespacestd; constintN=1010,M=1e5+10,MOD=1e9+7; intn; inta[N]; intf[N];//f[i]=a[0]~a[i]方案数 boolst[M]; vector<int>factor[M]; voidget_factor(vector<int>*factor,intm) { for(inti=1;i<m;i++) { for(intj=i*2;j<m;j+=i) factor[j].push_back(i); } } intget_sum(int*a,intindex) { //printf("\nindex:%d\n",index); memset(st,0,sizeof(st)); if(0==index)return1; longlongres=0; f
熟悉C#的人都清楚delegate,也清楚委托的作用。 实现观察者模式,在C++中的一种做法就是通过接口继承来实现,这无疑大大增加了耦合度。通过delegate变可以解除这种耦合。 下面是上班时间,偷偷实现的一个我的delegate。直接上码: #include<list> #include<functional> #include<iostream> #include<string> #include<algorithm> usingnamespacestd; #ifdef_DEBUG #defineOUTPUT(info)cout<<info<<endl<<endl; #else #defineOUTPUT(info) #endif namespacelixz { template<classC,typenameR,typename...Args> class_delegate_class_mem { public: typedefR(C::*class_func_ty
今天我们来说一说restframework中的版本操作的详解 首先我们先回顾一下restframework的流程: 请求进来走view,然后view调用视图的dispath函数 为了演示方便我们先来启一个项目: 在settings中INSTALLED_APPS添加rest_framework, 在view.py中创建一个视图类假使来个课程类吧: fromrest_framework.viewsimportAPIView fromrest_framework.responseimportResponse fromrest_framework.renderersimportJSONRenderer #只返回JS#,BrowsableAPIRenderer渲染器正常不用,容易出BUG fromdjango.shortcutsimportHttpResponse classCourseView(APIView): renderer_classes=[JSONRenderer,]#也可以在setting中设置 defget(self,request,*args,**kwargs):
如果采用直接cp的方法修改系统时区,那么就会把它所链接的文件修改掉,例如把美国的时区文件内容修改成了上海的时区内容,有可能会导致有些编程语言或程序在读取系统时区的时候发生错误,因此正确的修改方法是: CentOS6、Ubuntu16 #cp/usr/share/zoneinfo/Asia/Shanghai/etc/localtime复制 CentOS7、RHEL7、ScientificLinux7、OracleLinux7 最好的方法是使用timedatectl命令 #timedatectllist-timezones|grepShanghai#查找中国时区的完整名称 Asia/Shanghai #timedatectlset-timezoneAsia/Shanghai#其他时区以此类推复制 或者直接手动创建软链接 #ln-sf/usr/share/zoneinfo/Asia/Shanghai/etc/localtime复制