当前位置: 首页 > news >正文

网站设置反爬虫的常用方法有哪些网站免费下载安装大全手机版

网站设置反爬虫的常用方法有哪些,网站免费下载安装大全手机版,怎么制作gif动图,cms网站管理系统笔记内容转载自 AcWing 的 SpringBoot 框架课讲义#xff0c;课程链接#xff1a;AcWing SpringBoot 框架课。 CONTENTS 1. 配置WebSocket2. 前后端WebSocket通信2.1 WS通信的建立2.2 加入JWT验证 3. 前后端匹配业务3.1 实现前端页面3.2 实现前后端交互逻辑3.3 同步游戏地图 …笔记内容转载自 AcWing 的 SpringBoot 框架课讲义课程链接AcWing SpringBoot 框架课。 CONTENTS 1. 配置WebSocket2. 前后端WebSocket通信2.1 WS通信的建立2.2 加入JWT验证 3. 前后端匹配业务3.1 实现前端页面3.2 实现前后端交互逻辑3.3 同步游戏地图 我们的游戏之后是两名玩家对战因此需要实现联机功能在这之前还需要实现一个匹配系统能够匹配分数相近的玩家进行对战。 想要进行匹配就至少要有两个客户端当两个客户端都向服务器发送匹配请求后并不会马上得到返回结果一般会等待一段时间这个时间是未知的因此这个匹配是一个异步的过程对于这种异步的过程或者是计算量比较大的过程我们都会用一个额外的服务来操作。 那么这个额外的用于匹配的服务可以称为 Matching System这是另外一个程序进程当后端服务器接收到前端的请求后就会将请求发送给 Matching System这个匹配系统维护了一堆用户的集合它会不断地去匹配分数最接近的用户当匹配成功一组用户后就会将结果返回给后端服务器再由后端将匹配结果立即返回给对应的前端。这种服务就被称为微服务可以用 Spring Cloud 实现。 用以前的 HTTP 请求很难达到这种效果之前我们是在客户端向后端发送请求且后端在短时间内就会返回结果HTTP 请求只能满足这种一问一答式的服务。而我们现在需要实现的效果是客户端发送请求后不知道经过多长时间后端才会返回结果对于这种情况需要使用 WebSocket 协议WS该协议不仅支持客户端向服务器发送请求也支持服务器向客户端发送请求。 在前端向服务器发送请求后服务器会维护好一个 WS 链接这个链接其实就是一个 WebSocketServer 类的实例所有和这个链接相关的信息都会存到这个类中。 1. 配置WebSocket 我们之前每次刷新网页就会随机生成游戏地图该过程是在浏览器本地执行的当我们要实现匹配功能时地图就不能由两名玩家各自的客户端生成否则就基本不可能完全一样了。 当匹配成功后应该由服务器端创建一个 Game 任务将游戏放到该任务下执行统一生成地图且判断移动或者输赢等逻辑之后也应该移到后端来执行。 生成好地图后服务器就将地图传给两名玩家的前端然后等待玩家的键盘输入或者是 Bot 代码的输入Bot 代码的输入也属于一个微服务。 首先我们先在 pom.xml 文件中添加以下依赖 spring-boot-starter-websocketfastjson 接着在 config 包下创建 WebSocketConfig 配置类 package com.kob.backend.config;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter;Configuration public class WebSocketConfig {Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();} }然后我们创建一个 consumer 包在其中创建 WebSocketServer 类 package com.kob.backend.consumer;import org.springframework.stereotype.Component;import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint;Component ServerEndpoint(/websocket/{token}) // 注意不要以/结尾 public class WebSocketServer {OnOpenpublic void onOpen(Session session, PathParam(token) String token) {// 建立链接}OnClosepublic void onClose() {// 关闭链接}OnMessagepublic void onMessage(String message, Session session) {// 从Client接收消息}OnErrorpublic void onError(Session session, Throwable error) {error.printStackTrace();} }之前我们配置的 Spring Security 设置了屏蔽除了授权之外的其他所有链接因此我们需要在 SecurityConfig 类中放行一下 WebSocket 的链接 package com.kob.backend.config;import com.kob.backend.config.filter.JwtAuthenticationTokenFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;Configuration EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter {Autowiredprivate JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}BeanOverridepublic AuthenticationManager authenticationManagerBean() throws Exception { // AuthenticationManager用于处理身份验证return super.authenticationManagerBean();}Overrideprotected void configure(HttpSecurity http) throws Exception { // 配置HttpSecurityhttp.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests().antMatchers(/user/account/login/, /user/account/register/).permitAll() // 需要公开的链接在这边写即可.antMatchers(HttpMethod.OPTIONS).permitAll().anyRequest().authenticated();http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);}Overridepublic void configure(WebSecurity web) throws Exception {web.ignoring().antMatchers(/websocket/**);} }如果是使用新版的配置而不是使用 WebSecurityConfigurerAdapter 可以按以下方式配置 package com.kob.backend.config;import com.kob.backend.config.filter.JwtAuthenticationTokenFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;Configuration EnableWebSecurity public class SecurityConfig {Autowiredprivate JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}Beanpublic AuthenticationManager authenticationManagerBean(AuthenticationConfiguration authenticationConfiguration) throws Exception {return authenticationConfiguration.getAuthenticationManager();}Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {http.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests().antMatchers(/user/account/login/, /user/account/register/).permitAll().antMatchers(HttpMethod.OPTIONS).permitAll().anyRequest().authenticated();http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);return http.build();}Beanpublic WebSecurityCustomizer webSecurityCustomizer(){return (web) - web.ignoring().antMatchers(/websocket/**);} }2. 前后端WebSocket通信 2.1 WS通信的建立 WebSocket 不属于单例模式同一个时间每个类只能有一个实例我们每建一个 WS 链接都会新创建一个实例不是标准的 Spring 中的组件因此在注入 Mapper 时不能用 Autowired 直接注入一般是将 Autowired 写在一个 set() 方法上Spring 会根据方法的参数类型从 IoC 容器中找到该类型的 Bean 对象注入到方法的行参中并且自动反射调用该方法。 我们先假设前端传过来的是用户 ID 而不是 JWT 令牌 package com.kob.backend.consumer;import com.kob.backend.mapper.UserMapper; import com.kob.backend.pojo.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint;import java.io.IOException; import java.util.concurrent.ConcurrentHashMap;Component ServerEndpoint(/websocket/{token}) // 注意不要以/结尾 public class WebSocketServer {// ConcurrentHashMap是一个线程安全的哈希表用于将用户ID映射到WS实例private static final ConcurrentHashMapInteger, WebSocketServer users new ConcurrentHashMap();private User user;private Session session null;private static UserMapper userMapper;Autowiredpublic void setUserMapper(UserMapper userMapper) {WebSocketServer.userMapper userMapper;}OnOpenpublic void onOpen(Session session, PathParam(token) String token) {this.session session;System.out.println(Connected!);Integer userId Integer.parseInt(token);this.user userMapper.selectById(userId);users.put(userId, this);}OnClosepublic void onClose() {System.out.println(Disconnected!);if (this.user ! null) {users.remove(this.user.getId());}}OnMessagepublic void onMessage(String message, Session session) {System.out.println(Receive message!);}OnErrorpublic void onError(Session session, Throwable error) {error.printStackTrace();}public void sendMessage(String message) { // 从后端向当前链接发送消息synchronized (this.session) { // 由于是异步通信需要加一个锁try {this.session.getBasicRemote().sendText(message);} catch (IOException e) {e.printStackTrace();}}} }然后我们先在前端的 PKIndexView 组件中调试当组件被挂载完成后发出请求建立 WS 链接当被卸载后关闭 WS 链接 templatePlayGround / /templatescript import PlayGround from /components/PlayGround.vue; import { onMounted, onUnmounted } from vue; import { useStore } from vuex;export default {components: {PlayGround,},setup() {const store useStore();let socket null;let socket_url ws://localhost:3000/websocket/${store.state.user.id}/;onMounted(() {socket new WebSocket(socket_url);store.commit(updateOpponent, {username: 我的对手,photo: https://cdn.acwing.com/media/article/image/2022/08/09/1_1db2488f17-anonymous.png,});socket.onopen () { // 链接成功建立后会执行console.log(Connected!);store.commit(updateSocket, socket);};socket.onmessage (msg) { // 接收到后端消息时会执行const data JSON.parse(msg.data); // Spring传过来的数据是放在消息的data中console.log(data);};socket.onclose () { // 关闭链接后会执行console.log(Disconnected!);};});onUnmounted(() {socket.close(); // 如果不断开链接每次切换页面都会创建新链接就会导致有很多冗余链接});}, }; /scriptstyle scoped/style现在我们在对战页面每次刷新后都可以在浏览器控制台或后端控制台中看到 WS 的输出信息。 接下来我们要将 WebSocket 存到前端的 store 中在 store 目录下创建 pk.js 用来存储和对战页面相关的全局变量 export default {state: {status: matching, // 当前状态matching表示正在匹配playing表示正在对战socket: null, // 前端和后端建立的链接opponent_username: , // 对手的用户名opponent_photo: , // 对手的头像},getters: {},mutations: {updateSocket(state, socket) {state.socket socket;},updateOpponent(state, opponent) {state.opponent_username opponent.username;state.opponent_photo opponent.photo;},updateStatus(state, status) {state.status status;},},actions: {},modules: {}, };同时要在 store/index.js 中引入进来 import { createStore } from vuex; import ModuleUser from ./user; import ModulePk from ./pk;export default createStore({state: {},getters: {},mutations: {},actions: {},modules: {user: ModuleUser,pk: ModulePk,}, });2.2 加入JWT验证 现在我们直接使用用户的 ID 建立 WS 链接这是不安全的因为前端可以自行修改这个 ID因此就需要加入 JWT 验证。 WebSocket 中没有 Session 的概念因此我们在验证的时候前端就不用将信息放到表头里了直接放到链接中就行 ...script ...export default {...setup() {...let socket_url ws://localhost:3000/websocket/${store.state.user.jwt_token}/;...}, }; /script...验证的逻辑可以参考之前的 JwtAuthenticationTokenFilter我们可以把这个验证的模块单独写到一个文件中在 consumer 包下创建 utils 包然后创建一个 JwtAuthentication 类 package com.kob.backend.consumer.utils;import com.kob.backend.utils.JwtUtil; import io.jsonwebtoken.Claims;public class JwtAuthentication {public static Integer getUserId(String token) {int userId -1;try {Claims claims JwtUtil.parseJWT(token);userId Integer.parseInt(claims.getSubject());} catch (Exception e) {throw new RuntimeException(e);}return userId;} }然后就可以在 WebSocketServer 中解析 JWT 令牌 package com.kob.backend.consumer;import com.kob.backend.consumer.utils.JwtAuthentication; import com.kob.backend.mapper.UserMapper; import com.kob.backend.pojo.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint;import java.io.IOException; import java.util.concurrent.ConcurrentHashMap;Component ServerEndpoint(/websocket/{token}) // 注意不要以/结尾 public class WebSocketServer {...OnOpenpublic void onOpen(Session session, PathParam(token) String token) throws IOException {this.session session;System.out.println(Connected!);Integer userId JwtAuthentication.getUserId(token);this.user userMapper.selectById(userId);if (user ! null) {users.put(userId, this);} else {this.session.close();}}... }3. 前后端匹配业务 3.1 实现前端页面 我们需要实现一个前端的匹配页面并能够切换匹配和对战页面可以根据之前在 store 中存储的 status 状态来动态展示页面。首先在 components 目录下创建 MatchGround.vue 组件其中需要展示玩家自己的头像和用户名以及对手的头像和用户名当点击开始匹配按钮时向 WS 链接发送开始匹配的消息点击取消按钮时发送取消匹配的消息 templatediv classmatchgrounddiv classrowdiv classcol-md-6 styletext-align: center;div classphotoimg classimg-fluid :src$store.state.user.photo/divdiv classusername{{ $store.state.user.username }}/div/divdiv classcol-md-6 styletext-align: center;div classphotoimg classimg-fluid :src$store.state.pk.opponent_photo/divdiv classusername{{ $store.state.pk.opponent_username }}/div/divdiv classcol-md-12 text-center stylemargin-top: 14vh;button clickclick_match_btn typebutton classbtn btn-info btn-lg{{ match_btn_info }}/button/div/div/div /templatescript import { ref } from vue; import { useStore } from vuex;export default {setup() {const store useStore();let match_btn_info ref(开始匹配);const click_match_btn () {if (match_btn_info.value 开始匹配) {match_btn_info.value 取消;store.state.pk.socket.send(JSON.stringify({ // 将json封装成字符串发送给后端后端会在onMessage()中接到请求event: start_match, // 表示开始匹配}));} else {match_btn_info.value 开始匹配;store.state.pk.socket.send(JSON.stringify({event: stop_match, // 表示停止匹配}));}};return {match_btn_info,click_match_btn,};}, }; /scriptstyle scoped div.matchground {width: 60vw;height: 70vh;margin: 40px auto;border-radius: 10px;background-color: rgba(50, 50, 50, 0.5); }img {width: 35%;border-radius: 50%;margin: 14vh 0 1vh 0; }.username {font-size: 24px;font-weight: bold;color: white; } /style3.2 实现前后端交互逻辑 当用户点击开始匹配按钮后前端要向服务器发出一个请求后端接收到请求后应该将该用户放入匹配池中由于目前还没有实现微服务因此我们先在 WebSocketServer 后端用一个 Set 维护正在匹配的玩家当匹配池中满两名玩家就将其匹配在一起然后将匹配结果返回给两名玩家的前端 package com.kob.backend.consumer;import com.alibaba.fastjson2.JSONObject; import com.kob.backend.consumer.utils.JwtAuthentication; import com.kob.backend.mapper.UserMapper; import com.kob.backend.pojo.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint;import java.io.IOException; import java.util.Iterator; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArraySet;Component ServerEndpoint(/websocket/{token}) // 注意不要以/结尾 public class WebSocketServer {// ConcurrentHashMap是一个线程安全的哈希表用于将用户ID映射到WS实例private static final ConcurrentHashMapInteger, WebSocketServer users new ConcurrentHashMap();// CopyOnWriteArraySet也是线程安全的private static final CopyOnWriteArraySetUser matchPool new CopyOnWriteArraySet(); // 匹配池private User user;private Session session null;private static UserMapper userMapper;Autowiredpublic void setUserMapper(UserMapper userMapper) {WebSocketServer.userMapper userMapper;}OnOpenpublic void onOpen(Session session, PathParam(token) String token) throws IOException {this.session session;System.out.println(Connected!);Integer userId JwtAuthentication.getUserId(token);this.user userMapper.selectById(userId);if (user ! null) {users.put(userId, this);} else {this.session.close();}}OnClosepublic void onClose() {System.out.println(Disconnected!);if (this.user ! null) {users.remove(this.user.getId());matchPool.remove(this.user);}}OnMessagepublic void onMessage(String message, Session session) { // 一般会把onMessage()当作路由System.out.println(Receive message!);JSONObject data JSONObject.parseObject(message);String event data.getString(event); // 取出event的内容if (start_match.equals(event)) {this.startMatching();} else if (stop_match.equals(event)) {this.stopMatching();}}OnErrorpublic void onError(Session session, Throwable error) {error.printStackTrace();}public void sendMessage(String message) { // 从后端向当前链接发送消息synchronized (this.session) { // 由于是异步通信需要加一个锁try {this.session.getBasicRemote().sendText(message);} catch (IOException e) {e.printStackTrace();}}}private void startMatching() {System.out.println(Start matching!);matchPool.add(this.user);while (matchPool.size() 2) { // 临时调试用的未来要替换成微服务IteratorUser it matchPool.iterator();User a it.next(), b it.next();matchPool.remove(a);matchPool.remove(b);JSONObject respA new JSONObject(); // 发送给A的信息respA.put(event, match_success);respA.put(opponent_username, b.getUsername());respA.put(opponent_photo, b.getPhoto());users.get(a.getId()).sendMessage(respA.toJSONString()); // A不一定是当前链接因此要在users中获取JSONObject respB new JSONObject(); // 发送给B的信息respB.put(event, match_success);respB.put(opponent_username, a.getUsername());respB.put(opponent_photo, a.getPhoto());users.get(b.getId()).sendMessage(respB.toJSONString());}}private void stopMatching() {System.out.println(Stop matching!);matchPool.remove(this.user);} }接着修改一下 PKIndexView当接收到 WS 链接从后端发送过来的匹配成功消息后需要更新对手的头像和用户名 ...script ...export default {...setup() {...onMounted(() {...socket.onmessage (msg) { // 接收到后端消息时会执行const data JSON.parse(msg.data); // Spring传过来的数据是放在消息的data中console.log(data);if (data.event match_success) { // 匹配成功store.commit(updateOpponent, {username: data.opponent_username,photo: data.opponent_photo,});setTimeout(() { // 3秒后再进入游戏地图界面store.commit(updateStatus, playing);}, 3000);}};socket.onclose () { // 关闭链接后会执行console.log(Disconnected!);store.commit(updateStatus, matching); // 进入游戏地图后玩家点击其他页面应该是默认退出游戏};...});...}, }; /script...测试的时候需要用两个浏览器如果没有两个浏览器可以在 Edge 浏览器的右上角设置菜单中新建 InPrivate 窗口这样就可以自己登录两个不同的账号进行匹配测试。 3.3 同步游戏地图 现在匹配成功后两名玩家进入游戏时看到的地图是不一样的因为目前地图还都是在每名玩家本地的浏览器生成的那么我们就需要将生成地图的逻辑放到服务器端。 先在后端的 consumer.utils 包下创建 Game 类用来管理整个游戏流程然后我们在其中先实现地图的随机生成 package com.kob.backend.consumer.utils;import java.util.Arrays; import java.util.Random;public class Game {private final Integer rows;private final Integer cols;private final Integer inner_walls_count;private final boolean[][] g;private static final int[] dx { -1, 0, 1, 0 }, dy { 0, 1, 0, -1 };public Game(Integer rows, Integer cols, Integer inner_walls_count) {this.rows rows;this.cols cols;this.inner_walls_count inner_walls_count;this.g new boolean[rows][cols];}public boolean[][] getG() {return g;}private boolean check_connectivity(int sx, int sy, int tx, int ty) {if (sx tx sy ty) return true;g[sx][sy] true;for (int i 0; i 4; i) {int nx sx dx[i], ny sy dy[i];if (!g[nx][ny] check_connectivity(nx, ny, tx, ty)) {g[sx][sy] false; // 注意在这里我们用的g就是原始数组因此修改后要记得还原return true;}}g[sx][sy] false; // 记得还原return false;}private boolean drawMap() {// 初始化障碍物标记数组for (int i 0; i this.rows; i) {Arrays.fill(g[i], false);}// 给地图四周加上障碍物for (int r 0; r this.rows; r) {g[r][0] g[r][this.cols - 1] true;}for (int c 0; c this.cols; c) {g[0][c] g[this.rows - 1][c] true;}// 添加地图内部的随机障碍物需要有对称性因此枚举一半即可另一半对称生成Random random new Random();for (int i 0; i this.inner_walls_count / 2; i) {for (int j 0; j 10000; j) {int r random.nextInt(this.rows); // 返回0~this.rows-1的随机整数int c random.nextInt(this.cols);if (g[r][c] || g[this.rows - 1 - r][this.cols - 1 - c]) continue;if (r this.rows - 2 c 1 || r 1 c this.cols - 2) continue;g[r][c] g[this.rows - 1 - r][this.cols - 1 - c] true;break;}}return check_connectivity(this.rows - 2, 1, 1, this.cols - 2);}public void createMap() {for (int i 0; i 10000; i) {if (drawMap()) {break;}}} }然后在 WebSocketServer 类中当匹配成功时创建游戏地图暂时先将其存到局部变量中之后再进行优化 while (matchPool.size() 2) { // 临时调试用的未来要替换成微服务IteratorUser it matchPool.iterator();User a it.next(), b it.next();matchPool.remove(a);matchPool.remove(b);Game game new Game(13, 14, 20);game.createMap();JSONObject respA new JSONObject(); // 发送给A的信息respA.put(event, match_success);respA.put(opponent_username, b.getUsername());respA.put(opponent_photo, b.getPhoto());respA.put(game_map, game.getG());users.get(a.getId()).sendMessage(respA.toJSONString()); // A不一定是当前链接因此要在users中获取JSONObject respB new JSONObject(); // 发送给B的信息respB.put(event, match_success);respB.put(opponent_username, a.getUsername());respB.put(opponent_photo, a.getPhoto());respB.put(game_map, game.getG());users.get(b.getId()).sendMessage(respB.toJSONString()); }接下来需要在前端的 store/pk.js 文件中将地图存为全局变量 export default {state: {...game_map: null, // 游戏地图},getters: {},mutations: {...updateGameMap(state, game_map) {state.game_map game_map;},},actions: {},modules: {}, };在 PKIndexView.vue 中当接收到匹配成功的消息后需要更新地图 ...script ...export default {...setup() {...onMounted(() {...socket.onmessage (msg) { // 接收到后端消息时会执行const data JSON.parse(msg.data); // Spring传过来的数据是放在消息的data中console.log(data);if (data.event match_success) { // 匹配成功store.commit(updateOpponent, { // 更新对手信息username: data.opponent_username,photo: data.opponent_photo,});store.commit(updateGameMap, data.game_map); // 更新游戏地图setTimeout(() { // 3秒后再进入游戏地图界面store.commit(updateStatus, playing);}, 3000);}};...});...}, }; /script...然后需要在 GameMap.vue 中将全局变量传给游戏地图 GameMap.js ...script import { ref, onMounted } from vue; import { GameMap } from /assets/scripts/GameMap; import { useStore } from vuex;export default {setup() {const store useStore();let parent ref(null);let canvas ref(null);onMounted(() {new GameMap(canvas.value.getContext(2d), parent.value, store);});return {parent,canvas,};}, }; /script...最后就可以在 GameMap.js 中将地图渲染出来 ...export class GameMap extends AcGameObject {constructor(ctx, parent, store) { // ctx表示画布parent表示画布的父元素...this.store store;}...create_walls_online() { // 通过后端生成的数据创建地图const g this.store.state.pk.game_map;for (let r 0; r this.rows; r) {for (let c 0; c this.cols; c) {if (g[r][c]) {this.walls.push(new Wall(r, c, this));}}}}...start() {// for (let i 0; i 10000; i) {// if (this.create_walls())// break;// }this.create_walls_online(); // 在线生成地图this.add_listening_events();}... }
http://www.hkea.cn/news/14275050/

相关文章:

  • 做网站怎么添加背景图片建筑网站ad
  • 建设信用卡网站首页北京网站推广排名外包
  • 网站安全 维护wordpress png 压缩
  • 网站建设开发全包在哪里可以做个人网站
  • 黑科技软件网站宣传片拍摄公司排名
  • 广州白云区做网站网站正在建设中敬请
  • ps网站首页直线教程公司名称怎么取名
  • jsp网站开发详解 赵增敏线上平台推广方案
  • 外部网站跳转小程序WordPress 弹出二维码
  • 网站敏感词汇营销建设网站制作
  • 企业网站建设有什么要求网站开发项目需求分析书
  • 网站流量大小对网站有什么影响网站开发免责声明
  • 网站首页图片怎么更换价格低性价比高的汽车
  • 网站权重不稳定易班网站建设
  • 欧美做电影 迅雷下载网站济南网站设计公司推荐
  • 设计营销型网站域名前端开发人员招聘
  • 最好的网站模板世界搜索引擎大全
  • 企业网站设计 优帮云检察机关门户网站建设
  • 百度推广免费建站秦皇岛市卫生学校官网
  • 上海网站制作公司有哪些中装建设集团官网
  • 专门做旅游的视频网站有哪些广东省城乡建设部网站首页
  • 西安大网站建设公司seo排名点击软件运营
  • 厦门 网站建设 公司哪家好一级造价工程师报名时间
  • 全屏的翻页网站这么做lng企业自建站
  • 怎么创建一个自己的网站网站商城具有哪些功能模块
  • 网站制作公司兴田德润怎么联系腾讯如何做网站
  • 怎么建立一个网站的快捷方式市场推广12种推广渠道
  • 什么网站做二维码比较好菏泽网站备案拍照
  • 学校网站建设问卷调查特效制作软件
  • 网站域名跳转怎么做windows删除wordpress