├── UV_Grid_Sm.jpg ├── pages └── index │ ├── index.json │ ├── index.wxss │ ├── index.wxml │ ├── game │ ├── TurnTable.js │ ├── Pen.js │ └── index.js │ └── index.js ├── jsconfig.json ├── README.md ├── .vscode └── settings.json ├── sitemap.json ├── .idea ├── misc.xml ├── typescript-compiler.xml ├── modules.xml ├── chachach.iml └── workspace.xml ├── app.json ├── utils ├── utils │ └── util.js └── util.js ├── app.js ├── config.js ├── project.config.json ├── app.wxss ├── weui.wxss └── typings └── wx.d.ts /UV_Grid_Sm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanleung04/TrunTable/HEAD/UV_Grid_Sm.jpg -------------------------------------------------------------------------------- /pages/index/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": { 3 | 4 | }, 5 | "disableScroll": true 6 | } -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2015", 4 | "module": "commonjs" 5 | } 6 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TrunTable 2 | 微信小程序webgl实现转盘游戏 3 | 4 | 博客地址:这里这里 5 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.cjson": "jsonc", 4 | "*.wxss": "css", 5 | "*.wxs": "javascript", 6 | "*.wxml": "html" 7 | } 8 | } -------------------------------------------------------------------------------- /sitemap.json: -------------------------------------------------------------------------------- 1 | { 2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html", 3 | "rules": [{ 4 | "action": "allow", 5 | "page": "*" 6 | }] 7 | } -------------------------------------------------------------------------------- /pages/index/index.wxss: -------------------------------------------------------------------------------- 1 | .main { 2 | height: 200%; 3 | } 4 | 5 | .canvas-controller { 6 | position: fixed; 7 | width: 100%; 8 | height: 200rpx; 9 | background: #000; 10 | left: 0; 11 | bottom: 0; 12 | } -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /.idea/typescript-compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": [ 3 | "pages/index/index" 4 | ], 5 | "window": { 6 | "backgroundTextStyle": "light", 7 | "navigationBarBackgroundColor": "#fff", 8 | "navigationBarTextStyle": "white", 9 | "navigationStyle": "custom" 10 | }, 11 | "sitemapLocation": "sitemap.json" 12 | } -------------------------------------------------------------------------------- /.idea/chachach.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /utils/utils/util.js: -------------------------------------------------------------------------------- 1 | const formatTime = date => { 2 | const year = date.getFullYear() 3 | const month = date.getMonth() + 1 4 | const day = date.getDate() 5 | const hour = date.getHours() 6 | const minute = date.getMinutes() 7 | const second = date.getSeconds() 8 | 9 | return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':') 10 | } 11 | 12 | const formatNumber = n => { 13 | n = n.toString() 14 | return n[1] ? n : '0' + n 15 | } 16 | 17 | 18 | // 显示繁忙提示 19 | var showBusy = text => wx.showToast({ 20 | title: text, 21 | icon: 'loading', 22 | duration: 10000 23 | }) 24 | 25 | // 显示成功提示 26 | var showSuccess = text => wx.showToast({ 27 | title: text, 28 | icon: 'success' 29 | }) 30 | 31 | // 显示失败提示 32 | var showModel = (title, content) => { 33 | wx.hideToast(); 34 | 35 | wx.showModal({ 36 | title, 37 | content: JSON.stringify(content), 38 | showCancel: false 39 | }) 40 | } 41 | 42 | module.exports = { formatTime, showBusy, showSuccess, showModel } 43 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | //app.js 2 | var getConfigCount = 0; 3 | var app = ''; 4 | 5 | // const THREE = require('./utils/three.js') 6 | // const setting = require('./utils/setting.js') 7 | App({ 8 | onLaunch: function(option) { 9 | //调用API从本地缓存中获取数据 10 | app = this; 11 | 12 | 13 | this.setNavBarConfig() 14 | // this.getShare() 15 | }, 16 | 17 | SystemInfo: {}, 18 | 19 | globalData: {}, 20 | 21 | 22 | /** 23 | * 计算状态栏以及返回栏高度 24 | */ 25 | setNavBarConfig() { 26 | getConfigCount++; 27 | if (getConfigCount >= 100) return; 28 | try { 29 | let res = wx.getSystemInfoSync(); 30 | if (!res) { 31 | console.log('getConfig Fail'); 32 | app.setNavBarConfig(); 33 | return; 34 | } 35 | 36 | if (res.screenHeight <= 0 || res.screenWidth <= 0 || res.windowHeight <= 0 || res.windowWidth <= 0) { 37 | console.log('getConfig Fail'); 38 | app.setNavBarConfig(); 39 | return; 40 | } 41 | 42 | console.log('system res', res); 43 | this.SystemInfo = res; 44 | 45 | } catch (e) { 46 | console.log(e); 47 | } 48 | }, 49 | 50 | 51 | }); -------------------------------------------------------------------------------- /pages/index/game/TurnTable.js: -------------------------------------------------------------------------------- 1 | const THREE = require('../../../utils/three'); 2 | const Pen = require('./Pen'); 3 | /** 4 | * 转盘 5 | */ 6 | class TurnTable extends THREE.Group { 7 | static penTexture = null; 8 | static getTexture(canvas) { 9 | if (Pen.penTexture) { 10 | return Pen.penTexture 11 | } 12 | Pen.penTexture = new THREE.TextureLoader().load(canvas, '/UV_Grid_Sm.jpg'); 13 | return Pen.penTexture 14 | } 15 | canvas = null; 16 | // type = 'table'; 17 | constructor(canvas) { 18 | super() 19 | 20 | this.canvas = canvas; 21 | this.drawTurnTable(); 22 | } 23 | 24 | drawTurnTable() { 25 | // 纹理 26 | let circleTexture = TurnTable.getTexture(this.canvas); 27 | let material = new THREE.MeshBasicMaterial({ map: circleTexture }); 28 | // 圆 29 | let geometry = new THREE.CircleGeometry(100, 64); 30 | 31 | let turnTable = new THREE.Mesh(geometry, material); 32 | turnTable.name = 'table'; 33 | turnTable.position.set(0, 0, 0); 34 | this.radius = 100; 35 | this.add(turnTable); 36 | 37 | this.position.y = 200; 38 | 39 | 40 | // console.log(this.position); 41 | } 42 | } 43 | 44 | module.exports = TurnTable; -------------------------------------------------------------------------------- /utils/util.js: -------------------------------------------------------------------------------- 1 | const formatTime = date => { 2 | const year = date.getFullYear() 3 | const month = date.getMonth() + 1 4 | const day = date.getDate() 5 | const hour = date.getHours() 6 | const minute = date.getMinutes() 7 | const second = date.getSeconds() 8 | 9 | return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':') 10 | } 11 | 12 | const formatNumber = n => { 13 | n = n.toString() 14 | return n[1] ? n : '0' + n 15 | } 16 | 17 | const formatCountTime = date => { 18 | const hour = date.getUTCHours() 19 | const minute = date.getMinutes() 20 | const second = date.getSeconds() 21 | 22 | return [hour, minute, second].map(formatNumber).join(':') 23 | } 24 | 25 | 26 | // 显示繁忙提示 27 | var showBusy = text => wx.showToast({ 28 | title: text, 29 | icon: 'loading', 30 | duration: 10000 31 | }) 32 | 33 | // 显示成功提示 34 | var showSuccess = text => wx.showToast({ 35 | title: text, 36 | icon: 'success' 37 | }) 38 | 39 | // 显示失败提示 40 | var showModel = (title, content) => { 41 | wx.hideToast(); 42 | 43 | wx.showModal({ 44 | title, 45 | content: JSON.stringify(content), 46 | showCancel: false 47 | }) 48 | } 49 | 50 | module.exports = { formatTime, showBusy, showSuccess, showModel, formatCountTime } 51 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 小程序配置文件 3 | */ 4 | 5 | // 此处主机域名修改成腾讯云解决方案分配的域名 6 | // var host = 'wy.bleege.com'; 7 | 8 | // var host = 'test-wxa.bleege.com'; 9 | // var host = 'se8204.bleege.com'; 10 | // var host = 'cy.bleege.com'; 11 | // var host = 'sunmen.bleege.com'; 12 | var host = 'cy-test.bleege.com'; 13 | // var host = 'kg.bleege.com'; 14 | // var host = '192.168.19.214:8080'; 15 | 16 | // var content = 'yinyu' 17 | var content = 'idiom' 18 | var config = { 19 | 20 | // 下面的地址配合云端 Demo 工作 21 | service: { 22 | host, 23 | 24 | hostUrl: `https://${host}/${content}/api`, 25 | // hostUrl: `http://${host}/${content}/api`, 26 | // 登录地址,用于建立会话 27 | loginUrl: `https://${host}/${content}/api/v1/bleege/login`, 28 | // loginUrl: `http://${host}/${content}/api/v1/bleege/login`, 29 | // 非授权登陆地址 30 | unionLoginUrl: `https://${host}/${content}/api/v1/bleege/unionLogin`, 31 | // unionLoginUrl: `http://${host}/${content}/api/v1/bleege/unionLogin`, 32 | // 测试的请求地址,用于测试会话 33 | requestUrl: `https://${host}/${content}/api/user`, 34 | // requestUrl: `http://${host}/${content}/api/user`, 35 | 36 | // 测试的信道服务地址1 37 | tunnelUrl: `https://${host}/${content}/api/tunnel`, 38 | 39 | // 测试的上传地址 40 | uploadUrl: `https://${host}/${content}/api/upload`, 41 | 42 | avatarUrl: `https://${host}/${content}/static/images/avatar/0.png`, 43 | reportSourceUrl: 'https://kf.bleege.com/api/mina_source/report', 44 | 45 | originalId: 'gh_ff474f6f5ce9', 46 | 47 | version: '1.0.2', 48 | }, 49 | 50 | pixelRate: 0.5, //px与rpx换算关系 51 | platform: 'ios', //操作平台 用于适配胶囊高度 52 | capsuleHeight: 44, //胶囊高度 53 | statusBarHeight: 20, //手机顶部状态栏高度 54 | titleHeight: 136, //整个导航头高度 55 | systemHeight: 0, //手机屏幕高度 56 | isAllScreen: false, //是否是全面屏手机 57 | isHighHead: false, //是否是刘海屏手机 58 | windowWidth: 375, 59 | sampleRate: 44100, 60 | encodeBitRate: 64000, 61 | }; 62 | 63 | module.exports = config; -------------------------------------------------------------------------------- /pages/index/index.js: -------------------------------------------------------------------------------- 1 | //index.js 2 | //获取应用实例 3 | var app = getApp(); 4 | var THREE = require('../../utils/three') 5 | var requestAnimationFrame; 6 | var camera, scene, renderer; 7 | var mouseX = 0, 8 | mouseY = 0; 9 | var windowHalfX = 0; 10 | var windowHalfY = 0; 11 | var main = null; 12 | const Main = require('./game/index'); 13 | 14 | Page({ 15 | data: {}, 16 | onLoad: function() { 17 | 18 | }, 19 | onUnload() { 20 | main = null; 21 | }, 22 | onReady: function() { 23 | this.setData({ 24 | canvasWidth: app.SystemInfo.windowWidth * app.SystemInfo.pixelRatio, 25 | canvasHeight: (app.SystemInfo.windowHeight - 100) * app.SystemInfo.pixelRatio, 26 | canvasStyleWidth: app.SystemInfo.windowWidth + "px", 27 | canvasStyleHeight: (app.SystemInfo.windowHeight - 100) + "px", 28 | }, () => { 29 | var self = this; 30 | var query = wx.createSelectorQuery().select('#webgl').node(); 31 | query.exec((res) => { 32 | let canvas = res[0].node; 33 | requestAnimationFrame = canvas.requestAnimationFrame; 34 | 35 | canvas.width = app.SystemInfo.windowWidth * app.SystemInfo.pixelRatio; 36 | canvas.height = (app.SystemInfo.windowHeight - 100) * app.SystemInfo.pixelRatio; 37 | canvas.style = {}; 38 | canvas.style.width = canvas.width; 39 | canvas.style.height = canvas.height; 40 | console.log('canvas', canvas); 41 | main = new Main(canvas); 42 | }); 43 | }); 44 | 45 | }, 46 | addPen() { 47 | main.addPen(); 48 | }, 49 | makePenFly() { 50 | main.makePenFly(); 51 | }, 52 | clear() { 53 | main.clear(); 54 | }, 55 | 56 | onTouchStart: function(event) {}, 57 | onTouchMove: function(event) { 58 | // console.log(event); 59 | mouseX = (event.touches[0].clientX || event.touches[0].x - windowHalfX) * 3; 60 | mouseY = (event.touches[0].clientY || event.touches[0].y - windowHalfY) * 3; 61 | }, 62 | onTouchEnd: function(event) {}, 63 | }) -------------------------------------------------------------------------------- /project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "项目配置文件。", 3 | "setting": { 4 | "urlCheck": false, 5 | "es6": true, 6 | "enhance": false, 7 | "postcss": true, 8 | "minified": true, 9 | "newFeature": true, 10 | "coverView": true, 11 | "autoAudits": false, 12 | "checkInvalidKey": true, 13 | "checkSiteMap": true, 14 | "uploadWithSourceMap": true, 15 | "babelSetting": { 16 | "ignore": [], 17 | "disablePlugins": [], 18 | "outputPath": "" 19 | } 20 | }, 21 | "compileType": "miniprogram", 22 | "libVersion": "2.8.0", 23 | "appid": "wxcddc17929870f018", 24 | "projectname": "%E5%8F%89%E5%8F%89%E5%8F%89github", 25 | "simulatorType": "wechat", 26 | "simulatorPluginLibVersion": {}, 27 | "condition": { 28 | "search": { 29 | "current": -1, 30 | "list": [] 31 | }, 32 | "conversation": { 33 | "current": -1, 34 | "list": [] 35 | }, 36 | "plugin": { 37 | "current": -1, 38 | "list": [] 39 | }, 40 | "game": { 41 | "currentL": -1, 42 | "list": [] 43 | }, 44 | "miniprogram": { 45 | "current": 0, 46 | "list": [ 47 | { 48 | "id": 0, 49 | "name": "room", 50 | "pathName": "pageRoom/pages/room/room", 51 | "query": "gameStatus=3", 52 | "scene": null 53 | }, 54 | { 55 | "id": 1, 56 | "name": "startGame", 57 | "pathName": "pageRoom/pages/startGame/startGame", 58 | "query": "gameStatus=3", 59 | "scene": null 60 | }, 61 | { 62 | "id": 2, 63 | "name": "好友组队", 64 | "pathName": "pageRoom/pages/room/room", 65 | "query": "gameStatus=5&date=190624&roomId=331391", 66 | "scene": null 67 | }, 68 | { 69 | "id": -1, 70 | "name": "rank", 71 | "pathName": "/pages/rank/rank", 72 | "query": "", 73 | "scene": null 74 | }, 75 | { 76 | "id": 4, 77 | "name": "好友组队", 78 | "pathName": "pageRoom/pages/room/room", 79 | "query": "gameStatus=0&teamId=1143363923189178370", 80 | "scene": null 81 | }, 82 | { 83 | "id": -1, 84 | "name": "游戏回顾", 85 | "pathName": "pageRoom/pages/room/room", 86 | "query": "gameStatus=6", 87 | "scene": null 88 | }, 89 | { 90 | "id": -1, 91 | "name": "录音测试", 92 | "pathName": "pages/room/room", 93 | "query": "", 94 | "scene": null 95 | }, 96 | { 97 | "id": 7, 98 | "name": "bank", 99 | "pathName": "pages/index/index", 100 | "query": "status=3&userId=11471856", 101 | "scene": null 102 | } 103 | ] 104 | } 105 | } 106 | } -------------------------------------------------------------------------------- /pages/index/game/Pen.js: -------------------------------------------------------------------------------- 1 | const THREE = require('../../../utils/three'); 2 | const ray = new THREE.Raycaster(); 3 | class Pen extends THREE.Group { 4 | canvas = null; 5 | move = false; 6 | main = null; 7 | fall = false; 8 | static penTexture = null; 9 | static getTexture(canvas) { 10 | if (Pen.penTexture) { 11 | return Pen.penTexture 12 | } 13 | Pen.penTexture = new THREE.TextureLoader().load(canvas, '/UV_Grid_Sm.jpg'); 14 | return Pen.penTexture 15 | } 16 | constructor(canvas, main) { 17 | super(); 18 | this.main = main; 19 | this.canvas = canvas; 20 | // console.log('here'); 21 | this.drawPen(); 22 | } 23 | 24 | clone() { 25 | return super.clone(false); 26 | } 27 | pen = null; 28 | drawPen() { 29 | 30 | let material = new THREE.MeshBasicMaterial({ map: Pen.getTexture(this.canvas) }); 31 | let geometry = new THREE.PlaneGeometry(20, 60); 32 | let pen = new THREE.Mesh(geometry, material); 33 | this.pen = pen; 34 | pen.name = 'pen'; 35 | this.add(pen); 36 | // this.matrixAutoUpdate = true; 37 | this.position.set(0, -400, -1); 38 | } 39 | 40 | reset(main, canvas, deg) { 41 | this.main = main; 42 | this.canvas = canvas; 43 | this.position.set(0, -400, -1); 44 | // let deg = this.position.z 45 | // console.log('deg', deg); 46 | this.rotateZ(deg); 47 | // this.quaternion.z = 0; 48 | // console.log(this); 49 | // this.quaternion; 50 | // this.rotation = rotation; 51 | } 52 | 53 | flyPen(object) { 54 | if (this.fall) { 55 | this.fallPen(); 56 | return; 57 | } 58 | if (this.move) { 59 | this.position.y += 15; 60 | // 检测碰撞 61 | this.crashTest(object); 62 | 63 | // if (this.position.y > 0) { 64 | // this.move = false; 65 | // // this.main.penFlySuccess(100); 66 | // } 67 | } 68 | } 69 | 70 | fallPen() { 71 | // console.log('fall'); 72 | this.position.y -= 35; 73 | if (this.position.y == -500) { 74 | this.fall = false; 75 | } 76 | } 77 | 78 | // 碰撞检查 79 | crashTest(object) { 80 | let originPoint = this.position.clone(); 81 | originPoint.z = 100; 82 | // console.log(object); 83 | // return; 84 | for (let posIndex = 0; posIndex < this.pen.geometry.vertices.length; posIndex++) { 85 | // 原顶点坐标 86 | let localVertex = this.pen.geometry.vertices[posIndex].clone(); 87 | // 对顶点坐标作变换,获取变换后的真实坐标 88 | let globalVertex = localVertex.applyMatrix4(this.pen.matrix); 89 | // 刀对象的位置,因为这里的顶点位置都是在刀对象上的,所以计算方向向量要用到刀在group中的相对位置 90 | let pen_pos = this.pen.position.clone(); 91 | // 给 "高度" 92 | pen_pos.z = 100; 93 | // 坐标相减获取方向向量 94 | let directionVector = globalVertex.sub(pen_pos); 95 | // 设置射线 96 | ray.set(originPoint, directionVector.clone().normalize()) 97 | // 获取相交的对象,返回是一个数组 98 | let result = ray.intersectObjects(object.children, true) 99 | console.log(result); 100 | if (result.length > 0) { 101 | this.move = false; 102 | 103 | // if (result[0].object.name == 'table') { 104 | // this.main.penFlySuccess(result[0].distance); 105 | // } else { 106 | // this.main.penFlyFail(); 107 | // } 108 | break; 109 | } 110 | } 111 | } 112 | } 113 | 114 | module.exports = Pen; -------------------------------------------------------------------------------- /pages/index/game/index.js: -------------------------------------------------------------------------------- 1 | const app = getApp(); 2 | const THREE = require('../../../utils/three'); 3 | const TurnTable = require('./TurnTable'); 4 | const Pen = require('./Pen'); 5 | var requestAnimationFrame; 6 | class GameMain { 7 | canvas = null 8 | constructor(canvas) { 9 | this.canvas = canvas; 10 | requestAnimationFrame = canvas.requestAnimationFrame; 11 | this.init(canvas); 12 | this.animate(); 13 | } 14 | 15 | // 镜头 16 | camera = null; 17 | // 场景 18 | scene = null; 19 | // 灯光 20 | light = null; 21 | 22 | // 渲染器 23 | renderer = null; 24 | 25 | // 转盘 26 | turnTable = null; 27 | 28 | // 主场景 29 | mainObj = null; 30 | 31 | init(canvas) { 32 | 33 | // this.camera = new THREE.PerspectiveCamera() 34 | // 2d画面,直接用正交相机 35 | this.camera = new THREE.OrthographicCamera(canvas.width / -2, canvas.width / 2, canvas.height / 2, canvas.height / -2, 1, 500); 36 | // 设置相机位置 37 | this.camera.position.set(0, 0, 4); 38 | // 创建场景 39 | this.scene = new THREE.Scene(); 40 | // 设置背景色 41 | this.scene.background = new THREE.Color(0xffffff); 42 | // 设置灯光 43 | this.light = new THREE.PointLight(0xff0000, 1, 0); 44 | this.light.position.set(200, 200, 200); 45 | // 将灯光添加到场景 46 | this.scene.add(this.light); 47 | 48 | // 转盘 49 | this.turnTable = new TurnTable(canvas); 50 | // group 51 | this.mainObj = new THREE.Group(); 52 | this.mainObj.add(this.turnTable); 53 | this.scene.add(this.mainObj); 54 | 55 | 56 | this.renderer = new THREE.WebGLRenderer({ canvas: canvas, antalias: true }); 57 | this.renderer.setSize(canvas.width, canvas.height); 58 | this.addPen() 59 | } 60 | 61 | clear() { 62 | 63 | this.scene.remove(this.mainObj); 64 | // this.scene.dispose(); 65 | this.mainObj = null; 66 | this.turnTable = null; 67 | this.pen = null; 68 | if (this.gameStatus == 'fail') { 69 | this.restart() 70 | } else { 71 | this.gameStatus = 'restart' 72 | } 73 | 74 | } 75 | 76 | restart() { 77 | // 转盘 78 | this.gameStatus = 'start' 79 | this.turnTable = new TurnTable(this.canvas); 80 | // group 81 | this.mainObj = new THREE.Group(); 82 | this.mainObj.add(this.turnTable); 83 | this.scene.add(this.mainObj); 84 | this.addPen() 85 | 86 | // this.animate(); 87 | } 88 | 89 | // 碰撞一起转 90 | penFlySuccess(dis) { 91 | this.pen.move = false; 92 | this.turnTable.add(this.pen); 93 | // console.log('turnTable', this.turnTable.rotation.z); 94 | // console.log(-Math.cos(this.turnTable.rotation.z) * this.turnTable.radius); 95 | 96 | let deg = this.turnTable.rotation.z; 97 | dis = this.turnTable.radius + 15; 98 | console.log('dis', dis); 99 | this.pen.rotateZ(-deg); 100 | this.pen.position.x = -Math.sin(this.turnTable.rotation.z) * dis; 101 | // this.pen.position.y = -this.turnTable.radius; 102 | this.pen.position.y = this.pen.position.x * Math.cos(deg) / Math.sin(deg); 103 | // this.pen.position.y = -this.turnTable.radius; 104 | this.addPen(deg); 105 | } 106 | 107 | penFlyFail() { 108 | this.gameStatus = 'fail'; 109 | this.pen.fall = true; 110 | this.pen.move = false; 111 | wx.showToast({ 112 | title: 'gameover' 113 | }) 114 | } 115 | 116 | gameStatus = 'start' 117 | 118 | // 动画 119 | animate() { 120 | 121 | 122 | 123 | 124 | let self = this; 125 | requestAnimationFrame(() => { 126 | // console.log(this); 127 | this.animate(); 128 | }); 129 | 130 | this.render(); 131 | } 132 | 133 | render() { 134 | if (this.pen) { 135 | this.pen.flyPen(this.turnTable); 136 | } 137 | 138 | if (this.gameStatus == 'restart') { 139 | this.restart(); 140 | return; 141 | } 142 | if (this.gameStatus == 'start') { 143 | if (this.turnTable) { 144 | this.turnTable.rotateZ(0.05); 145 | } 146 | } 147 | 148 | 149 | // 弧度deg 150 | 151 | // this.pen.rotateZ(0.02); 152 | // console.log(this.turnTable.position) 153 | // this.turnTable.translateZ(0.02); 154 | // this.turnTable.position.x += 1; 155 | this.renderer.render(this.scene, this.camera); 156 | } 157 | 158 | // 159 | pen = null; 160 | penList = []; 161 | // 加刀 162 | 163 | addPen(deg = 0) { 164 | if (this.pen) { 165 | let pen = this.pen.clone() 166 | this.pen = pen; 167 | this.pen.reset(this, this.canvas, deg); 168 | this.mainObj.add(this.pen); 169 | return; 170 | } 171 | this.pen = new Pen(this.canvas, this); 172 | this.mainObj.add(this.pen); 173 | // this.penList.push(this.pen); 174 | } 175 | 176 | // 飞刀 177 | makePenFly() { 178 | this.pen.move = true; 179 | } 180 | } 181 | 182 | module.exports = GameMain; -------------------------------------------------------------------------------- /app.wxss: -------------------------------------------------------------------------------- 1 | /**app.wxss**/ 2 | 3 | /**app.wxss**/ 4 | @import 'weui.wxss'; 5 | 6 | .container { 7 | height: 100%; 8 | display: flex; 9 | flex-direction: column; 10 | /* align-items: center; *//* justify-content: space-between; *//* padding: 200rpx 20rpx; */ 11 | box-sizing: border-box; 12 | } 13 | 14 | .main-bg { 15 | width: 100%; 16 | position: fixed; 17 | bottom: 0; 18 | z-index: -1; 19 | left: 0; 20 | } 21 | 22 | page { 23 | /*background-color: #fbf9fe !important;*/ 24 | background-color: #f2f2f2 !important; 25 | /* background-color: #f5f6f5 ; */ 26 | height: 100%; 27 | font-family: Microsoft YaHei; 28 | } 29 | 30 | .page-body { 31 | width: 100%; 32 | flex-grow: 1; 33 | overflow-x: hidden; 34 | } 35 | 36 | .page-foot { 37 | padding: 0 0 34rpx 0; 38 | text-align: center; 39 | color: #1aad19; 40 | font-size: 0; 41 | } 42 | 43 | .foot2 { 44 | color: #586c94; 45 | font-size: 26rpx; 46 | display: inline-block; 47 | } 48 | 49 | .foot1 { 50 | margin: 0 auto; 51 | color: #888; 52 | font-size: 24rpx; 53 | } 54 | 55 | .content-container { 56 | height: 100%; 57 | display: flex; 58 | display: -webkit-flex; 59 | flex-direction: column; 60 | -webkit-flex-direction: column; 61 | } 62 | 63 | .content-body { 64 | flex-grow: 1; 65 | -webkit-flex-grow: 1; 66 | } 67 | 68 | .torecord { 69 | color: #586c94; 70 | font-size: 28rpx; 71 | display: inline-block; 72 | } 73 | 74 | .descript { 75 | margin: 0 auto; 76 | color: #888; 77 | font-size: 28rpx; 78 | } 79 | 80 | /* authorization modal */ 81 | 82 | .auth-container { 83 | position: absolute; 84 | height: 100%; 85 | width: 100%; 86 | left: 0; 87 | top: 0; 88 | background: rgba(0, 0, 0, 0.75); 89 | z-index: 900; 90 | display: flex; 91 | flex-direction: column; 92 | justify-content: center; 93 | align-items: center; 94 | } 95 | 96 | .auth-modal-container { 97 | margin: -64rpx 90rpx 0; 98 | background-color: white; 99 | border-radius: 8rpx; 100 | position: relative; 101 | } 102 | 103 | .auth-modal-title { 104 | font-size: 36rpx; 105 | color: black; 106 | font-weight: bold; 107 | height: 100rpx; 108 | line-height: 100rpx; 109 | text-align: center; 110 | border-bottom: 1rpx solid #eaeaea; 111 | } 112 | 113 | .auth-modal-content { 114 | margin-top: 42rpx; 115 | padding: 0 48rpx; 116 | font-size: 34rpx; 117 | color: #333; 118 | text-align: left; 119 | line-height: 1.5; 120 | } 121 | 122 | .auth-modal-content-tips { 123 | margin-top: 20rpx; 124 | padding: 0 48rpx; 125 | font-size: 30rpx; 126 | color: #ccc; 127 | text-align: left; 128 | line-height: 1.4; 129 | } 130 | 131 | .auth-btn-container { 132 | width: 100%; 133 | text-align: center; 134 | padding-bottom: 16rpx; 135 | margin-top: 42rpx; 136 | } 137 | 138 | .modal-auth-button { 139 | font-size: 34rpx !important; 140 | margin: 0 48rpx !important; 141 | font-weight: bold; 142 | } 143 | 144 | /* .song-list{ 145 | style="padding-bottom:64rpx;" 146 | } */ 147 | 148 | .song-info { 149 | display: flex; 150 | justify-content: space-between; 151 | border-bottom: 1rpx solid rgba(224, 224, 224, 0.6); 152 | padding: 30rpx 0 30rpx 0; 153 | align-items: center; 154 | overflow: visible; 155 | } 156 | 157 | .song-colunm { 158 | display: flex; 159 | flex-direction: column; 160 | } 161 | 162 | .song-row { 163 | display: flex; 164 | align-items: baseline; 165 | line-height: 1; 166 | overflow: hidden; 167 | text-overflow: ellipsis; 168 | white-space: nowrap; 169 | } 170 | 171 | .song-lyrics-row { 172 | display: block !important; 173 | margin-top: 26rpx; 174 | line-height: 36rpx; 175 | } 176 | 177 | .song-lyrics { 178 | font-size: 26rpx; 179 | color: #a5a5a5; 180 | } 181 | 182 | .song-title { 183 | display: flex; 184 | align-items: baseline; 185 | font-size: 30rpx; 186 | color: #333; 187 | /* line-height: 34rpx; */ 188 | height: 34rpx; 189 | } 190 | 191 | .song-listen { 192 | display: flex; 193 | font-size: 26rpx; 194 | padding: 0 20rpx; 195 | align-items: center; 196 | } 197 | 198 | .ic-play-btn { 199 | width: 16rpx; 200 | height: 20rpx; 201 | display: flex; 202 | /* margin-top: 10rpx; */ 203 | margin-left: 8rpx; 204 | } 205 | 206 | .ic-pause-btn { 207 | width: 23rpx; 208 | height: 23rpx; 209 | /* display: flex; */ 210 | margin-top: 9rpx; 211 | margin-left: 8rpx; 212 | } 213 | 214 | .song-lyrics { 215 | font-size: 26rpx; 216 | color: #a5a5a5; 217 | margin-right: 20rpx; 218 | } 219 | 220 | .song-artist { 221 | color: #ccc; 222 | font-size: 26rpx; 223 | margin-left: 10rpx; 224 | } 225 | 226 | .listen { 227 | display: flex; 228 | font-size: 26rpx; 229 | color: #efa150; 230 | line-height: 1; 231 | } 232 | 233 | .song-right { 234 | display: flex; 235 | align-items: center; 236 | height: 100%; 237 | /* width: 80rpx; */ 238 | position: relative; 239 | } 240 | 241 | .songlist-add, .songlist-del { 242 | display: flex; 243 | } 244 | 245 | .song-left { 246 | width: 600rpx; 247 | } 248 | 249 | .song-name { 250 | max-width: 290rpx; 251 | overflow: hidden; 252 | text-overflow: ellipsis; 253 | white-space: nowrap; 254 | } 255 | 256 | .ic-song-chose { 257 | height: 52rpx; 258 | width: 52rpx; 259 | } 260 | 261 | .bottom-bar { 262 | position: fixed; 263 | left: 0; 264 | bottom: -110rpx; 265 | z-index: 1003; 266 | height: 110rpx; 267 | width: 100%; 268 | background: #f5535e; 269 | display: flex; 270 | justify-content: space-between; 271 | align-items: center; 272 | transition: all 0.5s ease; 273 | } 274 | 275 | .bar-ani { 276 | bottom: 0; 277 | } 278 | 279 | .bar-left { 280 | display: flex; 281 | justify-content: center; 282 | align-items: center; 283 | position: relative; 284 | width: 162rpx; 285 | height: 100%; 286 | background: #ffd666; 287 | } 288 | 289 | .bar-right { 290 | /* display: flex; */ 291 | justify-content: center; 292 | align-items: center; 293 | flex: 1; 294 | height: 100%; 295 | color: #fff; 296 | font-size: 36rpx; 297 | } 298 | 299 | .ic-song-chose { 300 | height: 52rpx; 301 | width: 52rpx; 302 | } 303 | 304 | .chose-song-num { 305 | position: absolute; 306 | left: 106rpx; 307 | top: 22rpx; 308 | background-color: #f5535e; 309 | color: #fff; 310 | height: 28rpx; 311 | width: 28rpx; 312 | border-radius: 50%; 313 | text-align: center; 314 | line-height: 28rpx; 315 | font-size: 20rpx; 316 | } 317 | 318 | .select-list-mask { 319 | position: fixed; 320 | top: 0; 321 | left: 0; 322 | z-index: 1001; 323 | height: 100%; 324 | width: 100%; 325 | background: rgba(0, 0, 0, 0.6); 326 | } 327 | 328 | .select-list-box { 329 | position: fixed; 330 | bottom: 110rpx; 331 | left: 0; 332 | z-index: 1002; 333 | width: 100%; 334 | max-height: 100%; 335 | background: #fff; 336 | border-radius: 20rpx 20rpx 0 0; 337 | box-sizing: border-box; 338 | transition: all 0.3s linear; 339 | transform: translate3d(0, 140%, 0); 340 | } 341 | 342 | .select-list-bot { 343 | padding-bottom: 0; 344 | } 345 | 346 | .select-box-tip { 347 | font-size: 26rpx; 348 | color: #ccc; 349 | height: 80rpx; 350 | text-align: center; 351 | line-height: 80rpx; 352 | /* text-align: center; */ 353 | } 354 | 355 | .navbar-div { 356 | flex: 1; 357 | position: absolute; 358 | width: 100%; 359 | top: 96rpx; 360 | left: 0; 361 | bottom: 0; 362 | right: 0; 363 | } 364 | 365 | .word-area { 366 | /* padding-left: 32rpx; */ 367 | padding-top: 0; 368 | padding-bottom: 0; 369 | box-sizing: border-box; 370 | } 371 | 372 | .word-item { 373 | border: 0 !important; 374 | display: flex; 375 | padding: 40rpx 32rpx; 376 | } 377 | 378 | .container-bg { 379 | position: fixed; 380 | top: 0; 381 | bottom: 0; 382 | left: 0; 383 | right: 0; 384 | width: 100%; 385 | height: 100%; 386 | z-index: -1; 387 | background: #23174f; 388 | } 389 | 390 | .bg-t { 391 | position: absolute; 392 | top: 0; 393 | width: 100%; 394 | } 395 | 396 | .bg-b { 397 | position: absolute; 398 | bottom: 0; 399 | width: 100%; 400 | } 401 | 402 | .default-btn { 403 | padding: 0; 404 | margin: 0; 405 | border-radius: 0; 406 | background-color: transparent; 407 | } 408 | 409 | .default-btn::after { 410 | border: none; 411 | padding: 0; 412 | margin: 0; 413 | background: none; 414 | } 415 | 416 | .btn-click { 417 | transform: scale(0.9, 0.9)!important; 418 | opacity: 0.9!important 419 | } 420 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | mesh 64 | renderer 65 | 66 | 67 | 68 | 76 | 77 | 78 | 79 | 80 | true 81 | DEFINITION_ORDER 82 | 83 | 84 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 |