微信小程序使用stomp.js实现STOMP传输协议的实时聊天

简介:

uniapp开发的小程序中使用
本来使用websocket,后端同事使用了stomp协议,导致前端也需要对应修改。
在这里插入图片描述

如何使用

在static/js中新建stomp.js和websocket.js,然后在需要使用的页面引入监听代码+发送代码即可

代码如下:

位置:项目/pages/static/js/stomp.js
1.stomp.js

// Generated by CoffeeScript 1.7.1

/*
   Stomp Over WebSocket http://www.jmesnil.net/stomp-websocket/doc/ | Apache License V2.0

   Copyright (C) 2010-2013 [Jeff Mesnil](http://jmesnil.net/)
   Copyright (C) 2012 [FuseSource, Inc.](http://fusesource.com)
 */

   (function() {
    var Byte, Client, Frame, Stomp,
      __hasProp = {}.hasOwnProperty,
      __slice = [].slice;
  
    Byte = {
      LF: '\x0A',
      NULL: '\x00'
    };
  
    Frame = (function() {
      var unmarshallSingle;
  
      function Frame(command, headers, body) {
        this.command = command;
        this.headers = headers != null ? headers : {};
        this.body = body != null ? body : '';
      }
  
      Frame.prototype.toString = function() {
        var lines, name, skipContentLength, value, _ref;
        lines = [this.command];
        skipContentLength = this.headers['content-length'] === false ? true : false;
        if (skipContentLength) {
          delete this.headers['content-length'];
        }
        _ref = this.headers;
        for (name in _ref) {
          if (!__hasProp.call(_ref, name)) continue;
          value = _ref[name];
          lines.push("" + name + ":" + value);
        }
        if (this.body && !skipContentLength) {
          lines.push("content-length:" + (Frame.sizeOfUTF8(this.body)));
        }
        lines.push(Byte.LF + this.body);
        return lines.join(Byte.LF);
      };
  
      Frame.sizeOfUTF8 = function(s) {
        if (s) {
          return encodeURI(s).match(/%..|./g).length;
        } else {
          return 0;
        }
      };
  
      unmarshallSingle = function(data) {
        var body, chr, command, divider, headerLines, headers, i, idx, len, line, start, trim, _i, _j, _len, _ref, _ref1;
        divider = data.search(RegExp("" + Byte.LF + Byte.LF));
        headerLines = data.substring(0, divider).split(Byte.LF);
        command = headerLines.shift();
        headers = {};
        trim = function(str) {
          return str.replace(/^\s+|\s+$/g, '');
        };
        _ref = headerLines.reverse();
        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
          line = _ref[_i];
          idx = line.indexOf(':');
          headers[trim(line.substring(0, idx))] = trim(line.substring(idx + 1));
        }
        body = '';
        start = divider + 2;
        if (headers['content-length']) {
          len = parseInt(headers['content-length']);
          body = ('' + data).substring(start, start + len);
        } else {
          chr = null;
          for (i = _j = start, _ref1 = data.length; start <= _ref1 ? _j < _ref1 : _j > _ref1; i = start <= _ref1 ? ++_j : --_j) {
            chr = data.charAt(i);
            if (chr === Byte.NULL) {
              break;
            }
            body += chr;
          }
        }
        return new Frame(command, headers, body);
      };
  
      Frame.unmarshall = function(datas) {
        var frame, frames, last_frame, r;
        frames = datas.split(RegExp("" + Byte.NULL + Byte.LF + "*"));
        r = {
          frames: [],
          partial: ''
        };
        r.frames = (function() {
          var _i, _len, _ref, _results;
          _ref = frames.slice(0, -1);
          _results = [];
          for (_i = 0, _len = _ref.length; _i < _len; _i++) {
            frame = _ref[_i];
            _results.push(unmarshallSingle(frame));
          }
          return _results;
        })();
        last_frame = frames.slice(-1)[0];
        if (last_frame === Byte.LF || (last_frame.search(RegExp("" + Byte.NULL + Byte.LF + "*$"))) !== -1) {
          r.frames.push(unmarshallSingle(last_frame));
        } else {
          r.partial = last_frame;
        }
        return r;
      };
  
      Frame.marshall = function(command, headers, body) {
        var frame;
        frame = new Frame(command, headers, body);
        return frame.toString() + Byte.NULL;
      };
  
      return Frame;
  
    })();
  
    Client = (function() {
      var now;
  
      function Client(ws) {
        this.ws = ws;
        this.ws.binaryType = "arraybuffer";
        this.counter = 0;
        this.connected = false;
        this.heartbeat = {
          outgoing: 10000,
          incoming: 10000
        };
        this.maxWebSocketFrameSize = 16 * 1024;
        this.subscriptions = {};
        this.partialData = '';
      }
  
      Client.prototype.debug = function(message) {
        var _ref;
        return typeof window !== "undefined" && window !== null ? (_ref = window.console) != null ? _ref.log(message) : void 0 : void 0;
      };
  
      now = function() {
        if (Date.now) {
          return Date.now();
        } else {
          return new Date().valueOf;
        }
      };
  
      Client.prototype._transmit = function(command, headers, body) {
        var out;
        out = Frame.marshall(command, headers, body);
        if (typeof this.debug === "function") {
          this.debug(">>> " + out);
        }
        while (true) {
          if (out.length > this.maxWebSocketFrameSize) {
            this.ws.send(out.substring(0, this.maxWebSocketFrameSize));
            out = out.substring(this.maxWebSocketFrameSize);
            if (typeof this.debug === "function") {
              this.debug("remaining = " + out.length);
            }
          } else {
            return this.ws.send(out);
          }
        }
      };
  
      Client.prototype._setupHeartbeat = function(headers) {
        var serverIncoming, serverOutgoing, ttl, v, _ref, _ref1;
        if ((_ref = headers.version) !== Stomp.VERSIONS.V1_1 && _ref !== Stomp.VERSIONS.V1_2) {
          return;
        }
        _ref1 = (function() {
          var _i, _len, _ref1, _results;
          _ref1 = headers['heart-beat'].split(",");
          _results = [];
          for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
            v = _ref1[_i];
            _results.push(parseInt(v));
          }
          return _results;
        })(), serverOutgoing = _ref1[0], serverIncoming = _ref1[1];
        if (!(this.heartbeat.outgoing === 0 || serverIncoming === 0)) {
          ttl = Math.max(this.heartbeat.outgoing, serverIncoming);
          if (typeof this.debug === "function") {
            this.debug("send PING every " + ttl + "ms");
          }
          this.pinger = Stomp.setInterval(ttl, (function(_this) {
            return function() {
              _this.ws.send(Byte.LF);
              return typeof _this.debug === "function" ? _this.debug(">>> PING") : void 0;
            };
          })(this));
        }
        if (!(this.heartbeat.incoming === 0 || serverOutgoing === 0)) {
          ttl = Math.max(this.heartbeat.incoming, serverOutgoing);
          if (typeof this.debug === "function") {
            this.debug("check PONG every " + ttl + "ms");
          }
          return this.ponger = Stomp.setInterval(ttl, (function(_this) {
            return function() {
              var delta;
              delta = now() - _this.serverActivity;
              if (delta > ttl * 2) {
                if (typeof _this.debug === "function") {
                  _this.debug("did not receive server activity for the last " + delta + "ms");
                }
                return _this.ws.close();
              }
            };
          })(this));
        }
      };
  
      Client.prototype._parseConnect = function() {
        var args, connectCallback, errorCallback, headers;
        args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
        headers = {};
        switch (args.length) {
          case 2:
            headers = args[0], connectCallback = args[1];
            break;
          case 3:
            if (args[1] instanceof Function) {
              headers = args[0], connectCallback = args[1], errorCallback = args[2];
            } else {
              headers.login = args[0], headers.passcode = args[1], connectCallback = args[2];
            }
            break;
          case 4:
            headers.login = args[0], headers.passcode = args[1], connectCallback = args[2], errorCallback = args[3];
            break;
          default:
            headers.login = args[0], headers.passcode = args[1], connectCallback = args[2], errorCallback = args[3], headers.host = args[4];
        }
        return [headers, connectCallback, errorCallback];
      };
  
      Client.prototype.connect = function() {
        var args, errorCallback, headers, out;
        args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
        out = this._parseConnect.apply(this, args);
        headers = out[0], this.connectCallback = out[1], errorCallback = out[2];
        if (typeof this.debug === "function") {
          this.debug("Opening Web Socket...");
        }
        this.ws.onmessage = (function(_this) {
          return function(evt) {
            var arr, c, client, data, frame, messageID, onreceive, subscription, unmarshalledData, _i, _len, _ref, _results;
            data = typeof ArrayBuffer !== 'undefined' && evt.data instanceof ArrayBuffer ? (arr = new Uint8Array(evt.data), typeof _this.debug === "function" ? _this.debug("--- got data length: " + arr.length) : void 0, ((function() {
              var _i, _len, _results;
              _results = [];
              for (_i = 0, _len = arr.length; _i < _len; _i++) {
                c = arr[_i];
                _results.push(String.fromCharCode(c));
              }
              return _results;
            })()).join('')) : evt.data;
            _this.serverActivity = now();
            if (data === Byte.LF) {
              if (typeof _this.debug === "function") {
                _this.debug("<<< PONG");
              }
              return;
            }
            if (typeof _this.debug === "function") {
              _this.debug("<<< " + data);
            }
            unmarshalledData = Frame.unmarshall(_this.partialData + data);
            _this.partialData = unmarshalledData.partial;
            _ref = unmarshalledData.frames;
            _results = [];
            for (_i = 0, _len = _ref.length; _i < _len; _i++) {
              frame = _ref[_i];
              switch (frame.command) {
                case "CONNECTED":
                  if (typeof _this.debug === "function") {
                    _this.debug("connected to server " + frame.headers.server);
                  }
                  _this.connected = true;
                  _this._setupHeartbeat(frame.headers);
                  _results.push(typeof _this.connectCallback === "function" ? _this.connectCallback(frame) : void 0);
                  break;
                case "MESSAGE":
                  subscription = frame.headers.subscription;
                  onreceive = _this.subscriptions[subscription] || _this.onreceive;
                  if (onreceive) {
                    client = _this;
                    messageID = frame.headers["message-id"];
                    frame.ack = function(headers) {
                      if (headers == null) {
                        headers = {};
                      }
                      return client.ack(messageID, subscription, headers);
                    };
                    frame.nack = function(headers) {
                      if (headers == null) {
                        headers = {};
                      }
                      return client.nack(messageID, subscription, headers);
                    };
                    _results.push(onreceive(frame));
                  } else {
                    _results.push(typeof _this.debug === "function" ? _this.debug("Unhandled received MESSAGE: " + frame) : void 0);
                  }
                  break;
                case "RECEIPT":
                  _results.push(typeof _this.onreceipt === "function" ? _this.onreceipt(frame) : void 0);
                  break;
                case "ERROR":
                  _results.push(typeof errorCallback === "function" ? errorCallback(frame) : void 0);
                  break;
                default:
                  _results.push(typeof _this.debug === "function" ? _this.debug("Unhandled frame: " + frame) : void 0);
              }
            }
            return _results;
          };
        })(this);
        this.ws.onclose = (function(_this) {
          return function() {
            var msg;
            msg = "Whoops! Lost connection to " + _this.ws.url;
            if (typeof _this.debug === "function") {
              _this.debug(msg);
            }
            _this._cleanUp();
            return typeof errorCallback === "function" ? errorCallback(msg) : void 0;
          };
        })(this);
        return this.ws.onopen = (function(_this) {
          return function() {
            if (typeof _this.debug === "function") {
              _this.debug('Web Socket Opened...');
            }
            headers["accept-version"] = Stomp.VERSIONS.supportedVersions();
            headers["heart-beat"] = [_this.heartbeat.outgoing, _this.heartbeat.incoming].join(',');
            return _this._transmit("CONNECT", headers);
          };
        })(this);
      };
  
      Client.prototype.disconnect = function(disconnectCallback, headers) {
        if (headers == null) {
          headers = {};
        }
        this._transmit("DISCONNECT", headers);
        this.ws.onclose = null;
        this.ws.close();
        this._cleanUp();
        return typeof disconnectCallback === "function" ? disconnectCallback() : void 0;
      };
  
      Client.prototype._cleanUp = function() {
        this.connected = false;
        if (this.pinger) {
          Stomp.clearInterval(this.pinger);
        }
        if (this.ponger) {
          return Stomp.clearInterval(this.ponger);
        }
      };
  
      Client.prototype.send = function(destination, headers, body) {
        if (headers == null) {
          headers = {};
        }
        if (body == null) {
          body = '';
        }
        headers.destination = destination;
        return this._transmit("SEND", headers, body);
      };
  
      Client.prototype.subscribe = function(destination, callback, headers) {
        var client;
        if (headers == null) {
          headers = {};
        }
        if (!headers.id) {
          headers.id = "sub-" + this.counter++;
        }
        headers.destination = destination;
        this.subscriptions[headers.id] = callback;
        this._transmit("SUBSCRIBE", headers);
        client = this;
        return {
          id: headers.id,
          unsubscribe: function() {
            return client.unsubscribe(headers.id);
          }
        };
      };
  
      Client.prototype.unsubscribe = function(id) {
        delete this.subscriptions[id];
        return this._transmit("UNSUBSCRIBE", {
          id: id
        });
      };
  
      Client.prototype.begin = function(transaction) {
        var client, txid;
        txid = transaction || "tx-" + this.counter++;
        this._transmit("BEGIN", {
          transaction: txid
        });
        client = this;
        return {
          id: txid,
          commit: function() {
            return client.commit(txid);
          },
          abort: function() {
            return client.abort(txid);
          }
        };
      };
  
      Client.prototype.commit = function(transaction) {
        return this._transmit("COMMIT", {
          transaction: transaction
        });
      };
  
      Client.prototype.abort = function(transaction) {
        return this._transmit("ABORT", {
          transaction: transaction
        });
      };
  
      Client.prototype.ack = function(messageID, subscription, headers) {
        if (headers == null) {
          headers = {};
        }
        headers["message-id"] = messageID;
        headers.subscription = subscription;
        return this._transmit("ACK", headers);
      };
  
      Client.prototype.nack = function(messageID, subscription, headers) {
        if (headers == null) {
          headers = {};
        }
        headers["message-id"] = messageID;
        headers.subscription = subscription;
        return this._transmit("NACK", headers);
      };
  
      return Client;
  
    })();
  
    Stomp = {
      VERSIONS: {
        V1_0: '1.0',
        V1_1: '1.1',
        V1_2: '1.2',
        supportedVersions: function() {
          return '1.1,1.0';
        }
      },
      client: function(url, protocols) {
        var klass, ws;
        if (protocols == null) {
          protocols = ['v10.stomp', 'v11.stomp'];
        }
        klass = Stomp.WebSocketClass || WebSocket;
        ws = new klass(url, protocols);
        return new Client(ws);
      },
      over: function(ws) {
        return new Client(ws);
      },
      Frame: Frame
    };
  
    if (typeof exports !== "undefined" && exports !== null) {
      exports.Stomp = Stomp;
    }
  
    if (typeof window !== "undefined" && window !== null) {
      Stomp.setInterval = function(interval, f) {
        return window.setInterval(f, interval);
      };
      Stomp.clearInterval = function(id) {
        return window.clearInterval(id);
      };
      window.Stomp = Stomp;
    } else if (!exports) {
      self.Stomp = Stomp;
    }
  
  }).call(this);

位置:项目/pages/static/js/websocket.js
2.websocket.js

const Stomp = require('./stomp.js').Stomp;

let socketOpen = false
let socketMsgQueue = []

export default {
  client: null,
  init(url, header ,connectWS) {
    if (this.client) {
      return Promise.resolve(this.client)
    }

    return new Promise((resolve, reject) => {
      const ws = {
        send: this.sendMessage,
        onopen: null,
        onmessage: null,
        close: this.closeSocket,
      }

      wx.connectSocket({ url, header })

      wx.onSocketOpen(function (res) {
        console.log('WebSocket连接已打开!', res)

        socketOpen = true
        for (let i = 0; i < socketMsgQueue.length; i++) {
          ws.send(socketMsgQueue[i])
        }
        socketMsgQueue = []

        ws.onopen && ws.onopen()
      })

      wx.onSocketMessage(function (res) {
        ws.onmessage && ws.onmessage(res)
      })

      wx.onSocketError(function (res) {
        console.log('WebSocket 错误!', res)
      })

      wx.onSocketClose((res) => {
        this.client.disconnect()
        this.client = null
        socketOpen = false
        console.log('WebSocket 已关闭!', res)
        setTimeout(()=>{
          connectWS()
        },3000)
      })

      Stomp.setInterval = function (interval, f) {
        return setInterval(f, interval)
      }
      Stomp.clearInterval = function (id) {
        return clearInterval(id)
      }

      const client = (this.client = Stomp.over(ws))
      client.connect(header, function () {
        console.log('stomp connected')
        resolve(client)
      })
    })
  },
  disconnect() {
    wx.closeSocket()
  },
  sendMessage(message) {
    if (socketOpen) {
      wx.sendSocketMessage({
        data: message,
      })
    } else {
      socketMsgQueue.push(message)
    }
  },
  closeSocket() {
    console.log('closeSocket')
  },
}

3.监听+发送代码

import WebSocket from "../../static/js/websocket"
const app = getApp();
data: {
	objUid: '1',
	client: null,
	content: '发送的内容'
},
onLoad(options) {
	// stomp协议请求 
	this.initWS()
},
initWS() {
	WebSocket.init(
		`${app.globalData.WSURL}/chat`,
		// 传参
		{
			// login: 'admin',
			// passcode: 'admin',
		},
		// ws断开回调
		() => {
			this.initWS()
		}
	).then((client) => {
		this.setData({
			client: client
		})
		// 订阅
		client.subscribe(
			// 路径
			`/response/${app.globalData.uid}/${this.data.objUid}`,
			// 接收到的数据
			(res) => {
				console.log(res)
			},
			// 消息不会被确认接收,不确认每次连接都会推送
			// { ack: 'client' } 
		)
	})
},
// 直接调用发送即可
send() {
	this.data.client.send(
		// 路径
		`/child/${app.globalData.uid}/${this.data.objUid}`,
		// 自定义参数 http://jmesnil.net/stomp-websocket/doc/
		{},//priority: 9 
		// 发送文本
		JSON.stringify({ 'content': this.data.content })
	);
},

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

request+python操作文件导入

业务场景&#xff1a; 通常我们需要上传文件或者导入文件如何操作呢&#xff1f; 首先通过f12或者通过抓包查到请求接口的参数&#xff0c;例如&#xff1a; 图中标注的就是我们需要的参数&#xff0c;其中 name是参数名&#xff0c;filename是文件名&#xff0c;Content-Type是…

keil5 报错no target connected

场景&#xff1a;用ST_Link V2 在 keil5 中下载stm32程序 原因&#xff1a;线路连接错误 正确连接 注意&#xff1a;江科大stm32和stlink的接线&#xff0c;一定要对齐&#xff0c;我买的一个不是按照顺序接线的&#xff0c;需要仔细查看

OpenHarmony设备截屏的5种方式

本文转载自《OpenHarmony设备截屏的5种方式 》&#xff0c;作者westinyang 目录 方式1&#xff1a;系统控制中心方式2&#xff1a;OHScrcpy投屏工具方式3&#xff1a;DevEcoStudio截屏功能方式4&#xff1a;hdc shell snapshot_display方式5&#xff1a;hdc shell wukong持续关…

C++新经典 | C语言

目录 一、基础之查漏补缺 1.float精度问题 2.字符型数据 3.变量初值问题 4.赋值&初始化 5.头文件之<> VS " " 6.逻辑运算 7.数组 7.1 二维数组初始化 7.2 字符数组 8.字符串处理函数 8.1 strcat 8.2 strcpy 8.3 strcmp 8.4 strlen 9.函数 …

(笔记四)利用opencv识别标记视频中的目标

预操作&#xff1a; 通过cv2将视频的某一帧图片转为HSV模式&#xff0c;并通过鼠标获取对应区域目标的HSV值&#xff0c;用于后续的目标识别阈值区间的选取 img cv.imread(r"D:\data\123.png") img cv.cvtColor(img, cv.COLOR_BGR2HSV) plt.figure(1), plt.imshow…

JixiPix Artista Impresso Pro for mac(油画滤镜效果软件)

JixiPix Artista Impresso pro Mac是一款专业的图像编辑软件&#xff0c;专为Mac用户设计。它提供了各种高质量的图像编辑工具&#xff0c;可以帮助您创建令人惊叹的图像。该软件具有直观的用户界面&#xff0c;使您可以轻松地浏览和使用各种工具。 它还支持多种文件格式&…

CSS中如何实现弹性盒子布局(Flexbox)的换行和排序功能?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 换行&#xff08;Flexbox Wrapping&#xff09;⭐ 示例&#xff1a;实现换行⭐ 排序&#xff08;Flexbox Ordering&#xff09;⭐ 示例&#xff1a;实现排序⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得…

大模型开发05:PDF 翻译工具开发实战

大模型开发实战05:PDF 翻译工具开发实战 PDF-Translator 机器翻译是最广泛和基础的 NLP 任务 PDF-Translator PDF 翻译器是一个使用 AI 大模型技术将英文 PDF 书籍翻译成中文的工具。这个工具使用了大型语言模型 (LLMs),如 ChatGLM 和 OpenAI 的 GPT-3 以及 GPT-3.5 Turbo 来…

长胜证券:股票配资什么意思

股票配资是指假贷的方法来进行股票出资&#xff0c;是指出资者经过向配资公司或个人假贷&#xff0c;以增加其自有资金的杠杆份额&#xff0c;然后到达更高的收益。股票配资可以用于股票、期货、外汇等多种金融市场&#xff0c;一起也是一种危险较大的出资方法。本文将从多个视…

ios开发 swift5 苹果系统自带的图标 SF Symbols

文章目录 1.官网app的下载和使用2.使用代码 1.官网app的下载和使用 苹果官网网址&#xff1a;SF Symbols 通过上面的网址可以下载dmg, 安装到自己的mac上 貌似下面这样不能展示出动画&#xff0c;还是要使用动画的代码 .bounce.up.byLayer2.使用代码 UIKit UIImage(system…

RESTful API 面试必问

RESTful API是一种基于 HTTP 协议的 API 设计风格&#xff0c;它提供了一组规范和约束&#xff0c;使得客户端&#xff08;如 Web 应用程序、移动应用等&#xff09;和服务端之间的通信更加清晰、简洁和易于理解。 RESTful API 的设计原则 使用 HTTP 协议&#xff1a;RESTful …

基于神经网络的3D地质模型

地球科学家需要对地质环境进行最佳估计才能进行模拟或评估。 除了地质背景之外&#xff0c;建立地质模型还需要一整套数学方法&#xff0c;如贝叶斯网络、协同克里金法、支持向量机、神经网络、随机模型&#xff0c;以在钻井日志或地球物理信息确实稀缺或不确定时定义哪些可能是…

华为云云服务器评测|华为云云耀云服务器L实例使用教学

文章目录 教学小故事 教学 华为云云耀云服务器L实例是一款提供高效、可靠、安全的基础设施服务的云服务器。下面是使用教学&#xff1a; 登录华为云官网。 测评产品链接&#xff1a;https://www.huaweicloud.com/product/hecs-light.html 进入云耀云服务器管理控制台&#xf…

计算机视觉主要任务

计算机视觉&#xff1a;使用计算机及相关设备对生物视觉的一种模拟。 主要包含6大任务&#xff0c;图像分类&#xff0c;目标检测&#xff0c;目标跟踪&#xff0c;语义分割&#xff0c;实例分割&#xff0c;影像重构。 图像分类&#xff1a;根据图像信息中所反映的不同特征&am…

如何展开MES管理系统的数据建模工作

在建设MES管理系统时&#xff0c;需要根据企业的产品及制造特性开展数据建模&#xff0c;一般可以按照以下步骤进行。首先&#xff0c;要明确需求和目标&#xff0c;了解希望通过数据建模实现的具体目标&#xff0c;例如改善生产效率、优化质量管理或提供决策支持等。 然后&am…

《游戏编程模式》学习笔记(九)游戏循环 Sequencing Patterns

定义 一个游戏循环会在游玩时不断运行。 每一次循环&#xff0c;它都会无阻塞地处理玩家的输入&#xff0c;更新游戏的状态&#xff0c;渲染游戏。它追踪时间的消耗并控制游戏的速度。游戏循环需要做到始终以固定的速度运行游戏。 一个游戏循环中通常包含处理输入部分&#xf…

设计模式之组合模式

文章目录 一、介绍二、案例 一、介绍 组合模式(Composite Pattern)&#xff0c;属于结构型设计模式。组合模式常用于树形的数据结构&#xff0c;比如&#xff1a;多级菜单、部门层级关系、html文本中的dom树。它的特点是使用户对单个对象和组合对象的使用是相同的。 二、案例…

科技资讯|苹果Vision Pro头显申请游戏手柄专利和商标

苹果集虚拟现实和增强现实于一体的头戴式设备 Vision Pro 推出一个月后&#xff0c;美国专利局公布了两项苹果公司申请的游戏手柄专利&#xff0c;其中一项的专利图如下图所示。据 PatentlyApple 报道&#xff0c;虽然专利本身并不能保证苹果公司会推出游戏手柄&#xff0c;但是…

没有 JavaScript 计时器的自动播放轮播 - CSS 动画

先看效果&#xff1a; 再看代码&#xff08;查看更多&#xff09;&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>计时器</title><style>* {padding: 0;margin: 0;box-siz…

科大讯飞永久免费GPT入口来了!!!

讯飞GPT永久免费使用入口注册链接&#xff1a;讯飞星火认知大模型-AI大语言模型-星火大模型-科大讯飞。 登录讯飞账号后&#xff0c;点击进入体验。 进入体验页面后&#xff0c;选择景点推荐。 笔者让其写一篇关于讯飞GPT介绍的文案。 讯飞GPT是一款由讯飞公司推出的人工智能语…