string(7723) "{"docs":[{"id":"158579","text":"\u3010Python\u3011Tkinter\u56fe\u5f62\u754c\u9762\u8bbe\u8ba1\uff08GUI\uff09","intro":"\u76ee\u5f55\n\nECharts\n\u5f02\u6b65\u52a0\u8f7d\n\n\n\nECharts\r\n\u6570\u636e\u53ef\u89c6\u5316\u5728\u8fc7\u53bb\u51e0\u5e74\u4e2d\u53d6\u5f97\u4e86\u5de8\u5927\u8fdb\u5c55\u3002\u5f00\u53d1\u4eba\u5458\u5bf9\u53ef\u89c6\u5316\u4ea7\u54c1\u7684\u671f\u671b\u4e0d\u518d\u662f\u7b80\u5355\u7684\u56fe\u8868\u521b\u5efa\u5de5\u5177\uff0c\u800c\u662f\u5728\u4ea4\u4e92\u3001\u6027\u80fd\u3001\u6570\u636e\u5904\u7406\u7b49\u65b9\u9762\u6709\u66f4\u9ad8\u7684\u8981\u6c42\u3002\r\nchart.setOption({\r\n color: [\r\n ","username":"HGNET","tagsname":"","tagsid":"","catesname":"","catesid":"","createtime":"1641183196","_id":"158579"},{"id":"158620","text":"python\u4e4bgui-tkinter\u53ef\u89c6\u5316\u7f16\u8f91\u754c\u9762 \u81ea\u52a8\u751f\u6210\u4ee3\u7801","intro":"\u76ee\u5f55\n\nECharts\n\u5f02\u6b65\u52a0\u8f7d\n\n\n\nECharts\r\n\u6570\u636e\u53ef\u89c6\u5316\u5728\u8fc7\u53bb\u51e0\u5e74\u4e2d\u53d6\u5f97\u4e86\u5de8\u5927\u8fdb\u5c55\u3002\u5f00\u53d1\u4eba\u5458\u5bf9\u53ef\u89c6\u5316\u4ea7\u54c1\u7684\u671f\u671b\u4e0d\u518d\u662f\u7b80\u5355\u7684\u56fe\u8868\u521b\u5efa\u5de5\u5177\uff0c\u800c\u662f\u5728\u4ea4\u4e92\u3001\u6027\u80fd\u3001\u6570\u636e\u5904\u7406\u7b49\u65b9\u9762\u6709\u66f4\u9ad8\u7684\u8981\u6c42\u3002\r\nchart.setOption({\r\n color: [\r\n ","username":"darkspr","tagsname":"","tagsid":"","catesname":"","catesid":"","createtime":"1641183190","_id":"158620"},{"id":"158603","text":"python3.6 +tkinter GUI\u7f16\u7a0b \u5b9e\u73b0\u754c\u9762\u5316\u7684\u6587\u672c\u5904\u7406\u5de5\u5177","intro":"\u76ee\u5f55\n\nECharts\n\u5f02\u6b65\u52a0\u8f7d\n\n\n\nECharts\r\n\u6570\u636e\u53ef\u89c6\u5316\u5728\u8fc7\u53bb\u51e0\u5e74\u4e2d\u53d6\u5f97\u4e86\u5de8\u5927\u8fdb\u5c55\u3002\u5f00\u53d1\u4eba\u5458\u5bf9\u53ef\u89c6\u5316\u4ea7\u54c1\u7684\u671f\u671b\u4e0d\u518d\u662f\u7b80\u5355\u7684\u56fe\u8868\u521b\u5efa\u5de5\u5177\uff0c\u800c\u662f\u5728\u4ea4\u4e92\u3001\u6027\u80fd\u3001\u6570\u636e\u5904\u7406\u7b49\u65b9\u9762\u6709\u66f4\u9ad8\u7684\u8981\u6c42\u3002\r\nchart.setOption({\r\n color: [\r\n ","username":"chenyuebai","tagsname":"","tagsid":"","catesname":"","catesid":"","createtime":"1641183187","_id":"158603"},{"id":"27850","text":"Python GUI\u4e4btkinter\u7a97\u53e3\u89c6\u7a97\u6559\u7a0b\u5927\u96c6\u5408\uff08\u770b\u8fd9\u7bc7\u5c31\u591f\u4e86\uff09 - \u6d2a\u536b","intro":"\u76ee\u5f55\n\nECharts\n\u5f02\u6b65\u52a0\u8f7d\n\n\n\nECharts\r\n\u6570\u636e\u53ef\u89c6\u5316\u5728\u8fc7\u53bb\u51e0\u5e74\u4e2d\u53d6\u5f97\u4e86\u5de8\u5927\u8fdb\u5c55\u3002\u5f00\u53d1\u4eba\u5458\u5bf9\u53ef\u89c6\u5316\u4ea7\u54c1\u7684\u671f\u671b\u4e0d\u518d\u662f\u7b80\u5355\u7684\u56fe\u8868\u521b\u5efa\u5de5\u5177\uff0c\u800c\u662f\u5728\u4ea4\u4e92\u3001\u6027\u80fd\u3001\u6570\u636e\u5904\u7406\u7b49\u65b9\u9762\u6709\u66f4\u9ad8\u7684\u8981\u6c42\u3002\r\nchart.setOption({\r\n color: [\r\n ","username":"shwee","tagsname":"","tagsid":"","catesname":"","catesid":"","createtime":"1641183186","_id":"27850"},{"id":"158605","text":"Python GUI\u7f16\u7a0b(Tkinter) windows\u754c\u9762\u5f00\u53d1","intro":"\u76ee\u5f55\n\nECharts\n\u5f02\u6b65\u52a0\u8f7d\n\n\n\nECharts\r\n\u6570\u636e\u53ef\u89c6\u5316\u5728\u8fc7\u53bb\u51e0\u5e74\u4e2d\u53d6\u5f97\u4e86\u5de8\u5927\u8fdb\u5c55\u3002\u5f00\u53d1\u4eba\u5458\u5bf9\u53ef\u89c6\u5316\u4ea7\u54c1\u7684\u671f\u671b\u4e0d\u518d\u662f\u7b80\u5355\u7684\u56fe\u8868\u521b\u5efa\u5de5\u5177\uff0c\u800c\u662f\u5728\u4ea4\u4e92\u3001\u6027\u80fd\u3001\u6570\u636e\u5904\u7406\u7b49\u65b9\u9762\u6709\u66f4\u9ad8\u7684\u8981\u6c42\u3002\r\nchart.setOption({\r\n color: [\r\n ","username":"itfat","tagsname":"","tagsid":"","catesname":"","catesid":"","createtime":"1641183184","_id":"158605"},{"id":"28228","text":"tkinter python\uff08\u56fe\u5f62\u5f00\u53d1\u754c\u9762\uff09","intro":"\u76ee\u5f55\n\nECharts\n\u5f02\u6b65\u52a0\u8f7d\n\n\n\nECharts\r\n\u6570\u636e\u53ef\u89c6\u5316\u5728\u8fc7\u53bb\u51e0\u5e74\u4e2d\u53d6\u5f97\u4e86\u5de8\u5927\u8fdb\u5c55\u3002\u5f00\u53d1\u4eba\u5458\u5bf9\u53ef\u89c6\u5316\u4ea7\u54c1\u7684\u671f\u671b\u4e0d\u518d\u662f\u7b80\u5355\u7684\u56fe\u8868\u521b\u5efa\u5de5\u5177\uff0c\u800c\u662f\u5728\u4ea4\u4e92\u3001\u6027\u80fd\u3001\u6570\u636e\u5904\u7406\u7b49\u65b9\u9762\u6709\u66f4\u9ad8\u7684\u8981\u6c42\u3002\r\nchart.setOption({\r\n color: [\r\n ","username":"yudanqu","tagsname":"","tagsid":"","catesname":"","catesid":"","createtime":"1641183159","_id":"28228"},{"id":"158613","text":"Tkinter\u56fe\u5f62\u754c\u9762\u8bbe\u8ba1\uff08GUI\uff09","intro":"\u76ee\u5f55\n\nECharts\n\u5f02\u6b65\u52a0\u8f7d\n\n\n\nECharts\r\n\u6570\u636e\u53ef\u89c6\u5316\u5728\u8fc7\u53bb\u51e0\u5e74\u4e2d\u53d6\u5f97\u4e86\u5de8\u5927\u8fdb\u5c55\u3002\u5f00\u53d1\u4eba\u5458\u5bf9\u53ef\u89c6\u5316\u4ea7\u54c1\u7684\u671f\u671b\u4e0d\u518d\u662f\u7b80\u5355\u7684\u56fe\u8868\u521b\u5efa\u5de5\u5177\uff0c\u800c\u662f\u5728\u4ea4\u4e92\u3001\u6027\u80fd\u3001\u6570\u636e\u5904\u7406\u7b49\u65b9\u9762\u6709\u66f4\u9ad8\u7684\u8981\u6c42\u3002\r\nchart.setOption({\r\n color: [\r\n ","username":"pywjh","tagsname":"","tagsid":"","catesname":"","catesid":"","createtime":"1641183158","_id":"158613"},{"id":"341361","text":"\u91cf\u5316\u5206\u6790\u83b7\u53d6\u6570\u636e\u76843\u79cd\u59ff\u52bf\uff08\u538b\u7bb1\u5e95\u7684\u795e\u5668Tushare\uff09","intro":"\u76ee\u5f55\n\nECharts\n\u5f02\u6b65\u52a0\u8f7d\n\n\n\nECharts\r\n\u6570\u636e\u53ef\u89c6\u5316\u5728\u8fc7\u53bb\u51e0\u5e74\u4e2d\u53d6\u5f97\u4e86\u5de8\u5927\u8fdb\u5c55\u3002\u5f00\u53d1\u4eba\u5458\u5bf9\u53ef\u89c6\u5316\u4ea7\u54c1\u7684\u671f\u671b\u4e0d\u518d\u662f\u7b80\u5355\u7684\u56fe\u8868\u521b\u5efa\u5de5\u5177\uff0c\u800c\u662f\u5728\u4ea4\u4e92\u3001\u6027\u80fd\u3001\u6570\u636e\u5904\u7406\u7b49\u65b9\u9762\u6709\u66f4\u9ad8\u7684\u8981\u6c42\u3002\r\nchart.setOption({\r\n color: [\r\n ","username":"casual","tagsname":"","tagsid":"","catesname":"","catesid":"","createtime":"1641183069","_id":"341361"},{"id":"238879","text":"\u9762\u5411\u4ea4\u6613\u7684\u65e5\u5185\u9ad8\u9891\u91cf\u5316\u4ea4\u6613\u5e73\u53f0\u7b14\u8bb0","intro":"\u76ee\u5f55\n\nECharts\n\u5f02\u6b65\u52a0\u8f7d\n\n\n\nECharts\r\n\u6570\u636e\u53ef\u89c6\u5316\u5728\u8fc7\u53bb\u51e0\u5e74\u4e2d\u53d6\u5f97\u4e86\u5de8\u5927\u8fdb\u5c55\u3002\u5f00\u53d1\u4eba\u5458\u5bf9\u53ef\u89c6\u5316\u4ea7\u54c1\u7684\u671f\u671b\u4e0d\u518d\u662f\u7b80\u5355\u7684\u56fe\u8868\u521b\u5efa\u5de5\u5177\uff0c\u800c\u662f\u5728\u4ea4\u4e92\u3001\u6027\u80fd\u3001\u6570\u636e\u5904\u7406\u7b49\u65b9\u9762\u6709\u66f4\u9ad8\u7684\u8981\u6c42\u3002\r\nchart.setOption({\r\n color: [\r\n ","username":"TaiYangXiManYouZhe","tagsname":"","tagsid":"","catesname":"","catesid":"","createtime":"1641183067","_id":"238879"},{"id":"238890","text":"2021 \u6700\u65b0\u91cf\u5316\u6295\u8d44\u4ea4\u6613\u8d44\u6e90\u6c47\u603b","intro":"\u76ee\u5f55\n\nECharts\n\u5f02\u6b65\u52a0\u8f7d\n\n\n\nECharts\r\n\u6570\u636e\u53ef\u89c6\u5316\u5728\u8fc7\u53bb\u51e0\u5e74\u4e2d\u53d6\u5f97\u4e86\u5de8\u5927\u8fdb\u5c55\u3002\u5f00\u53d1\u4eba\u5458\u5bf9\u53ef\u89c6\u5316\u4ea7\u54c1\u7684\u671f\u671b\u4e0d\u518d\u662f\u7b80\u5355\u7684\u56fe\u8868\u521b\u5efa\u5de5\u5177\uff0c\u800c\u662f\u5728\u4ea4\u4e92\u3001\u6027\u80fd\u3001\u6570\u636e\u5904\u7406\u7b49\u65b9\u9762\u6709\u66f4\u9ad8\u7684\u8981\u6c42\u3002\r\nchart.setOption({\r\n color: [\r\n ","username":"xgqfrms","tagsname":"","tagsid":"","catesname":"","catesid":"","createtime":"1641183063","_id":"238890"}],"count":535118}" array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(6) "158579" ["text"]=> string(46) "【Python】Tkinter图形界面设计(GUI)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(5) "HGNET" ["tagsname"]=> string(0) "" ["tagsid"]=> string(0) "" ["catesname"]=> string(0) "" ["catesid"]=> string(0) "" ["createtime"]=> string(10) "1641183196" ["_id"]=> string(6) "158579" } [1]=> array(10) { ["id"]=> string(6) "158620" ["text"]=> string(60) "python之gui-tkinter可视化编辑界面 自动生成代码" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "darkspr" ["tagsname"]=> string(0) "" ["tagsid"]=> string(0) "" ["catesname"]=> string(0) "" ["catesid"]=> string(0) "" ["createtime"]=> string(10) "1641183190" ["_id"]=> string(6) "158620" } [2]=> array(10) { ["id"]=> string(6) "158603" ["text"]=> string(66) "python3.6 +tkinter GUI编程 实现界面化的文本处理工具" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(10) "chenyuebai" ["tagsname"]=> string(0) "" ["tagsid"]=> string(0) "" ["catesname"]=> string(0) "" ["catesid"]=> string(0) "" ["createtime"]=> string(10) "1641183187" ["_id"]=> string(6) "158603" } [3]=> array(10) { ["id"]=> string(5) "27850" ["text"]=> string(80) "Python GUI之tkinter窗口视窗教程大集合(看这篇就够了) - 洪卫" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(5) "shwee" ["tagsname"]=> string(0) "" ["tagsid"]=> string(0) "" ["catesname"]=> string(0) "" ["catesid"]=> string(0) "" ["createtime"]=> string(10) "1641183186" ["_id"]=> string(5) "27850" } [4]=> array(10) { ["id"]=> string(6) "158605" ["text"]=> string(45) "Python GUI编程(Tkinter) windows界面开发" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(5) "itfat" ["tagsname"]=> string(0) "" ["tagsid"]=> string(0) "" ["catesname"]=> string(0) "" ["catesid"]=> string(0) "" ["createtime"]=> string(10) "1641183184" ["_id"]=> string(6) "158605" } [5]=> array(10) { ["id"]=> string(5) "28228" ["text"]=> string(39) "tkinter python(图形开发界面)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "yudanqu" ["tagsname"]=> string(0) "" ["tagsid"]=> string(0) "" ["catesname"]=> string(0) "" ["catesid"]=> string(0) "" ["createtime"]=> string(10) "1641183159" ["_id"]=> string(5) "28228" } [6]=> array(10) { ["id"]=> string(6) "158613" ["text"]=> string(34) "Tkinter图形界面设计(GUI)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(5) "pywjh" ["tagsname"]=> string(0) "" ["tagsid"]=> string(0) "" ["catesname"]=> string(0) "" ["catesid"]=> string(0) "" ["createtime"]=> string(10) "1641183158" ["_id"]=> string(6) "158613" } [7]=> array(10) { ["id"]=> string(6) "341361" ["text"]=> string(68) "量化分析获取数据的3种姿势(压箱底的神器Tushare)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(6) "casual" ["tagsname"]=> string(0) "" ["tagsid"]=> string(0) "" ["catesname"]=> string(0) "" ["catesid"]=> string(0) "" ["createtime"]=> string(10) "1641183069" ["_id"]=> string(6) "341361" } [8]=> array(10) { ["id"]=> string(6) "238879" ["text"]=> string(51) "面向交易的日内高频量化交易平台笔记" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(18) "TaiYangXiManYouZhe" ["tagsname"]=> string(0) "" ["tagsid"]=> string(0) "" ["catesname"]=> string(0) "" ["catesid"]=> string(0) "" ["createtime"]=> string(10) "1641183067" ["_id"]=> string(6) "238879" } [9]=> array(10) { ["id"]=> string(6) "238890" ["text"]=> string(41) "2021 最新量化投资交易资源汇总" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "xgqfrms" ["tagsname"]=> string(0) "" ["tagsid"]=> string(0) "" ["catesname"]=> string(0) "" ["catesid"]=> string(0) "" ["createtime"]=> string(10) "1641183063" ["_id"]=> string(6) "238890" } } ["count"]=> int(535118) } 制作3D小汽车游戏(下) - 爱码网
vadim-web

书接上回,这一节我们分模块说一说怎么写一个这样的游戏

1. 初始化场景、相机和渲染器

这几乎是绘制three必须做的事情,我们有两套场景和相机,一个是主场景和相机,另一个是小地图的场景和相机(用来俯视建筑和小汽车),渲染器设置一级曝光,输出编码设置为sRGBEncoding,代码如下。

scene = new THREE.Scene();
scene.background = new THREE.Color(0x8FBCD4);
scene.fog = new THREE.Fog(0x8FBCD4, 3000, 4000);

camera = new THREE.PerspectiveCamera(60, window.innerWidth/window.innerHeight, 0.1, 10000);
camera.position.set(10,10,10);
            
scene2 = new THREE.Scene();
scene2.background = new THREE.Color(0xffffff);

camera2 = new THREE.OrthographicCamera(-400, 400, 400, -400, 1, 1000);
camera2.position.set(0, 1000, 0);
camera2.lookAt(0,0,0);

renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1;
this.$refs.box.appendChild(renderer.domElement);

2. 设置地面和建筑

地面很简单,就是一个plane

initGround() {
    const ground_geom = new THREE.PlaneBufferGeometry(8000, 8000);
    const ground_mate = new THREE.MeshLambertMaterial({color: 0xBCD48F, side: THREE.DoubleSide});
    const ground_mesh = new THREE.Mesh(ground_geom, ground_mate);
    ground_mesh.rotation.x = - Math.PI / 2;
    scene.add(ground_mesh);
},

设置建筑,我们需要给每一个建筑设置长宽高、颜色、位置,并把它们放到一个组里,然后然需要给每一个建筑初始化一个OBB,并把这些OBB信息添加到一个数组中,便于我们日后做碰撞检测

initBuild(num) {
    let color = new THREE.Color();
    let build = new THREE.Group();
    for(let i=0; i<num; i++) {
        let w = Math.random() * 50 + 50;
        let h = Math.random() * 100 + 100;
        let d = Math.random() * 50 + 50;
        let x = Math.random() * 8000 - 4000;
        let z = Math.random() * 8000 - 4000;
        if((x * x + z * z) < Math.pow(140, 2)) {
            //40为车半长的估计值
            x = Math.pow(140, 2) / x;
            z = Math.pow(140, 2) / z;
        }
        let geometry = new THREE.BoxBufferGeometry(w, h, d);
        let material = new THREE.MeshStandardMaterial({color: new THREE.Color().setHSL(Math.random(), 1.0, 0.6)});
        let mesh = new THREE.Mesh(geometry, material);
        mesh.position.set(x, h / 2, z);
        build.add(mesh);
        let obb = new OBB();
        buildObbArray.push(obb.set(new THREE.Vector3(x, h / 2, z), new THREE.Vector3(w/2, h/2, d/2), new THREE.Matrix3()));
    }
    scene.add(build);
    scene2.add(build.clone());
},

3. 初始化小汽车

这里我们要下载好一个小汽车的模型,首先把模型设置成我们想要的大小,这里车高设置成10,其他维度等比例改变,然后找到方向盘,轮子等部分,添加到全局的组中,便于我们控制。

initCar() {
    const shadowTexture = new THREE.TextureLoader().load(\'/static/gltf/super_car/super_car_ao.png\');
    const loader = new GLTFLoader();
    const dracoLoader = new DRACOLoader();
    dracoLoader.setDecoderPath(\'/static/gltf/\');
    loader.setDRACOLoader(dracoLoader);
    loader.load(\'/static/gltf/super_car/super_car.glb\', gltf => {
        const model = gltf.scene.children[0];
        model.rotation.y = -Math.PI / 2;
        steering_wheel = model.getObjectByName(\'steering_wheel\');[]
        
        const shadow = new THREE.Mesh(
            new THREE.PlaneBufferGeometry( 0.655 * 4, 1.3 * 4 ),
            new THREE.MeshBasicMaterial( {
                map: shadowTexture, blending: THREE.MultiplyBlending, toneMapped: false, transparent: true
            } )
        );
        shadow.position.y = 0.1;
        shadow.rotation.x = - Math.PI / 2;
        model.add(shadow);

        const size = new THREE.Box3().setFromObject(model).getSize(new THREE.Vector3());
        model.scale.copy(new THREE.Vector3().addScalar(carHeight / size.y));
        carHalfSize = new THREE.Box3().setFromObject(model).getSize(new THREE.Vector3()).multiplyScalar(0.4);
        
        car.add(model);
        tyreArray.push(car.getObjectByName(\'wheel_fl\'),car.getObjectByName(\'wheel_fr\'),car.getObjectByName(\'wheel_rl\'),car.getObjectByName(\'wheel_rr\'));
        car.userData.obb = new OBB(new THREE.Vector3(0,5,0), carHalfSize, new THREE.Matrix3());
        scene.add(car);
        orthoCar = new THREE.Mesh(new THREE.SphereBufferGeometry(20, 20), new THREE.MeshBasicMaterial({color: 0xff0000, side: THREE.DoubleSide}));
        orthoCar.rotation.x = - Math.PI / 2;
        scene2.add(orthoCar);
    } );
},

4. 添加事件、转弯、增减速和切换视角

这里我们主要使用q–切换视角,a,d–转弯,w,s–加减速。

document.addEventListener(\'keypress\', event => {
    if(event.key == \'d\') {
        this.turn(0);
    } else if(event.key == \'a\') {
        this.turn(1);
    } else if(event.key == \'w\') {
        this.speed(1);
    } else if(event.key == \'s\') {
        this.speed(0)
    } else if(event.key == \'q\') {
        view = view == 0 ? 1 : 0;
    }
})

对于速度的控制,sp代表左右方向

speed(sp) {
    if(sp == 0 && speed > 0) {
        speed -= 2;
    } else if(sp == 0 && speed > -10) {
        speed -= 0.5;
    } else if(sp == 1 && speed < 40) {
        speed += 0.5;
    }
},

对于转弯的控制,我们用多段控制模拟非线性

turn(direct) {
    //模拟非线性转向
    if(direct == 0 && rotateTyre > -rotateMax * 0.5) {
        rotateTyre -= 0.02;
    } else if (direct == 0 && rotateTyre > -rotateMax * 0.8) {
        rotateTyre -= 0.04;
    } else if (direct == 0 && rotateTyre > -rotateMax) {
        rotateTyre -= 0.06;
    } else if(direct == 1 && rotateTyre < rotateMax * 0.5) {
        rotateTyre += 0.02;
    } else if(direct == 1 && rotateTyre < rotateMax * 0.8) {
        rotateTyre += 0.04;
    } else if(direct == 1 && rotateTyre < rotateMax) {
        rotateTyre += 0.06;
    }
    tyreArray[0].rotation.y = rotateTyre;
    tyreArray[1].rotation.y = rotateTyre;
    //方向盘
    steering_wheel.rotation.y = - rotateTyre;
},

5. 渲染

因为我们有两个场景要渲染,这里就选择渲染两次

render() {
    stats.update();
    this.run();
    renderer.setScissor( 0, 0, window.innerWidth, window.innerWidth );
    renderer.setViewport( 0, 0, window.innerWidth, window.innerHeight );
    renderer.setScissorTest(true);
    renderer.render( scene, camera );
    renderer.setScissor( 0, 0, window.innerHeight/4, window.innerHeight/4 );
    renderer.setViewport( 0, 0, window.innerHeight/4, window.innerHeight/4);
    renderer.setScissorTest(true);
    renderer.render( scene2, camera2 );
    this.globalID = requestAnimationFrame(this.render);
}

run方法里面控制着车的角度,车子的位置,轮子的传动,相机的位置,相机的lookAt,以及碰撞检测,这里面有我们上一节复习的有向包围盒OBB和欧拉角的使用

run() {
    let delta = - clock.getDelta();
    //轮胎转动∝速度
    tyreArray.forEach(d => d.rotation.copy(new THREE.Euler(delta * speed + d.rotation.x, d.rotation.y, d.rotation.z, \'ZYX\')));
    //rotateOffset 旋转偏移量  rotateTyre轮胎偏转  rotateCorrection偏转系数  speed车速
    let rotateOffset = Math.sin(rotateTyre) * rotateCorrection * speed;
    //rotateRun 旋转偏移总量
    rotateRun += rotateOffset;
    //rotateVector 车前进方向向量(不断乘offset得到)
    rotateVector.applyAxisAngle(new THREE.Vector3(0,1,0), rotateOffset);
    //车x和z方向增加量 ∝车速
    car.position.x += speed * speedCorrection * rotateVector.x;
    car.position.z += speed * speedCorrection * rotateVector.z;
    camera2.position.set(car.position.x, 1000, car.position.z);
    camera2.lookAt(car.position.x, 10, car.position.z);
    orthoCar.position.copy(car.position);
    //车身旋转 使用 旋转偏移总量rotateRun
    car.rotation.y = rotateRun;
    //切换视角
    if(view == 0) {
        camera.position.set(car.position.x - 3 * Math.sin(rotateRun), 8, car.position.z - 3 * Math.cos(rotateRun));
        camera.lookAt(camera.position.x + Math.cos(rotateRun), 8, camera.position.z - Math.sin(rotateRun));
    } else {
        camera.position.set(car.position.x + 50 * Math.cos(rotateRun + Math.PI * 0.9), 20, car.position.z - 50 * Math.sin(rotateRun + Math.PI * 0.9));
        camera.lookAt(camera.position.x + Math.cos(rotateRun), 19.9, camera.position.z - Math.sin(rotateRun));
    }
    //判断是否碰撞
    car.userData.obb.set(car.position, carHalfSize, new THREE.Matrix3().setFromMatrix4(car.matrixWorld));
    const obb = car.userData.obb;
    for(let i=0; i<buildObbArray.length; i++) {
        const obbTest = buildObbArray[i];
        if(obb.intersectsOBB(obbTest) === true) {
            speed = 0;
        }
    }
},

这里我们直接遍历建筑的OBB数组然后通过intersectsOBB方法,判断是否相撞就可以了。

 

转载请注明地址:郭先生的博客

分类:

技术点:

相关文章:

  • 2021-12-29
  • 2021-11-12
  • 2021-12-22
  • 2022-01-01
  • 2021-08-30
  • 2021-12-03
  • 2021-11-14
猜你喜欢
  • 2020-12-23
  • 2021-09-22
  • 2021-08-30
  • 2021-10-26
  • 2021-11-11
  • 2021-12-10
  • 2021-08-30
相关资源
相似解决方案