Commit 0ea1b78f authored by Master Q's avatar Master Q

打包配置

parent 18f37e0e
node_modules/ node_modules/
released/
\ No newline at end of file
This diff is collapsed.
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
margin: auto; margin: auto;
background: #ffffff; background: #ffffff;
z-index: 1000; z-index: 1000;
left: 0;
top: 0;
} }
.load-container .boxLoading { .load-container .boxLoading {
width: 50px; width: 50px;
...@@ -92,16 +94,28 @@ ...@@ -92,16 +94,28 @@
} }
} }
#stage {
/* width: 812px !important;
height: 375px !important;
display: block; */
/* transform: rotate(90deg);
transform-origin: center center; */
}
</style> </style>
<script src="//yun.duiba.com.cn/aurora/assets/4723050c150b41f362ecf483e9cf98eb31c4a15b.js"></script> <script src="//yun.duiba.com.cn/aurora/assets/4723050c150b41f362ecf483e9cf98eb31c4a15b.js"></script>
</head> </head>
<body> <body>
<div class="load-container"> <canvas id="stage"></canvas>
<div class="boxLoading"></div> <script type="importmap">
</div> {
"imports": {
"bundle": "/bundle.js"
}
}
</script>
<!-- 这里的 bundle 就是 webpack 临时打包出来 --> <!-- 这里的 bundle 就是 webpack 临时打包出来 -->
<script src="/bundle.js"></script> <script src="output.js"></script>
<script> <script type="module">
window.addEventListener("load", function () { window.addEventListener("load", function () {
// window.screen.orientation.lock("landscape-primary"); // window.screen.orientation.lock("landscape-primary");
window['showLoading'] = function() { window['showLoading'] = function() {
...@@ -110,6 +124,11 @@ ...@@ -110,6 +124,11 @@
window['hideLoading'] = function() { window['hideLoading'] = function() {
document.querySelector('.load-container').style.display = 'none' document.querySelector('.load-container').style.display = 'none'
} }
Ammo().then(() => {
const dome = document.getElementById('stage')
new StageScene(dome)
})
}) })
</script> </script>
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -5,7 +5,12 @@ ...@@ -5,7 +5,12 @@
"main": "index.ts", "main": "index.ts",
"scripts": { "scripts": {
"dev": "node ./scripts/devServer -p 9016", "dev": "node ./scripts/devServer -p 9016",
"build": "webpack" "build": "webpack --config webpack.prod.js",
"handleRes": "node scripts/delRel && node scripts/copyRes && node scripts/imageMin",
"upload": "node scripts/upload",
"prod": "npm run handleRes && npm run upload && npm run buildTS",
"buildWeb": "npm run handleRes && node scripts/upload 1",
"buildTS": "webpack --config webpack.prod.js && node scripts/mergeJs"
}, },
"keywords": [ "keywords": [
"three", "three",
...@@ -16,14 +21,23 @@ ...@@ -16,14 +21,23 @@
"dependencies": { "dependencies": {
"@types/three": "^0.144.0", "@types/three": "^0.144.0",
"oimo": "^1.0.9", "oimo": "^1.0.9",
"three": "^0.144.0", "three": "^0.144.0"
"ts-loader": "^9.3.1",
"typescript": "^4.7.4",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.9.3"
}, },
"devDependencies": { "devDependencies": {
"webpack-merge": "^5.8.0" "ali-oss": "^4.11.4",
"chalk": "^2.3.0",
"co": "^4.6.0",
"del": "2.2.1",
"imagemin": "^7.0.1",
"imagemin-mozjpeg": "^8.0.0",
"imagemin-pngquant": "^8.0.0",
"pngquant": "^4.0.0",
"progress": "^2.0.0",
"ts-loader": "^4.0.0",
"typescript": "^4.8.3",
"webpack": "^4.1.0",
"webpack-cli": "^3.1.1",
"webpack-dev-server": "^3.1.0",
"webpack-merge": "^4.1.2"
} }
} }
{
"type": "activity",
"name": "template"
}
\ No newline at end of file
var fs = require('fs');
var path = require("path");
function writeFile(p, text) {
fs.writeFile(p, text, function (err) {
// if (!err)
// console.log("写入成功!")
})
}
//递归创建目录 同步方法
function mkdirsSync(dirname) {
if (fs.existsSync(dirname)) {
return true;
} else {
if (mkdirsSync(path.dirname(dirname))) {
// console.log("mkdirsSync = " + dirname);
fs.mkdirSync(dirname);
return true;
}
}
}
function _copy(src, dist) {
var paths = fs.readdirSync(src)
paths.forEach(function (p) {
var _src = src + '/' + p;
var _dist = dist + '/' + p;
var stat = fs.statSync(_src)
if (stat.isFile()) {// 判断是文件还是目录
fs.writeFileSync(_dist, fs.readFileSync(_src));
} else if (stat.isDirectory()) {
copyDir(_src, _dist)// 当是目录是,递归复制
}
})
}
/*
* 复制目录、子目录,及其中的文件
* @param src {String} 要复制的目录
* @param dist {String} 复制到目标目录
*/
function copyDir(src, dist) {
var b = fs.existsSync(dist)
// console.log("dist = " + dist)
if (!b) {
// console.log("mk dist = ",dist)
mkdirsSync(dist);//创建目录
}
// console.log("_copy start")
_copy(src, dist);
}
function createDocs(src, dist, callback) {
// console.log("createDocs...")
copyDir(src, dist);
// console.log("copyDir finish exec callback")
if (callback) {
callback();
}
}
createDocs("./resource", "./released/resource/", function () {
console.log("资源拷贝成功")
})
\ No newline at end of file
var fs = require("fs");
function createHtml(url) {
var js = `//yun.duiba.com.cn/db_games/${url}/output.js`;
var template = fs.readFileSync("./index.html").toString();
//写入released
fs.writeFileSync("./released/index.html", template.replace("output.js", js))
}
module.exports = createHtml
\ No newline at end of file
var fs = require("fs");
var del = require('del');
function delDir(path, isSelf) {
let files = [];
if (fs.existsSync(path)) {
files = fs.readdirSync(path);
files.forEach((file, index) => {
let curPath = path + "/" + file;
if (fs.statSync(curPath).isDirectory()) {
delDir(curPath); //递归删除文件夹
} else {
fs.unlinkSync(curPath); //删除文件
}
});
if (!isSelf) fs.rmdirSync(path);
}
}
var paths = './released/';//设置删除路径
// delDir(paths, true);//删除文件夹
del(paths).then(() => {
fs.mkdirSync(paths);
}).catch(()=>{
fs.mkdirSync(paths);
})
\ No newline at end of file
...@@ -35,19 +35,31 @@ const webpackDevServer = require('webpack-dev-server'); ...@@ -35,19 +35,31 @@ const webpackDevServer = require('webpack-dev-server');
const webpack = require('webpack'); const webpack = require('webpack');
const config = require('../webpack.dev.js'); const config = require('../webpack.dev.js');
const options = {
open: true,
contentBase: '.',
hot: true,
host: 'localhost',
};
// webpackDevServer.addDevServerEntrypoints(config, options); webpackDevServer.addDevServerEntrypoints(config, options);
const compiler = webpack(config); const compiler = webpack(config);
const server = new webpackDevServer(config.devServer, compiler); const server = new webpackDevServer(compiler, options);
// 8080
server.listen(+argv[argv.indexOf("-p") + 1], '0.0.0.0', () => {
const runServer = async () => { });
const ipV4 = await webpackDevServer.internalIP('v4')
console.log('========== ipV4 ==========', ipV4)
server.options.host = ipV4
const argvPort = +argv[argv.indexOf("-p") + 1] // const runServer = async () => {
argvPort && (server.options.port = +argv[argv.indexOf("-p") + 1]) // // const ipV4 = await webpackDevServer.internalIP('v4')
await server.start() // // console.log('========== ipV4 ==========', ipV4)
} // // server.options.host = ipV4
// const argvPort = +argv[argv.indexOf("-p") + 1]
// argvPort && (server.options.port = +argv[argv.indexOf("-p") + 1])
// await server.start()
// }
runServer() // runServer()
\ No newline at end of file \ No newline at end of file
const imagemin = require('imagemin');
// const imageminJpegtran = require('imagemin-jpegtran');imagemin-mozjpeg
const imageminJpegtran = require('imagemin-mozjpeg');
const imageminPngquant = require('imagemin-pngquant');
var fs = require('fs');
var path = require('path');
// 要处理的图片文件夹路径
var altasPath = "./released/resource/"
var folders = getFolders(altasPath);
folders.map(async function (folder) {
const files = await imagemin([altasPath + folder + '/*.{png,jpg}'], {
destination: altasPath + folder,
plugins: [
imageminJpegtran(),
imageminPngquant({
quality: [0.6, 0.8]
})
]
});
if (files && files.length) {
files.forEach((v) => {
console.log("压缩图片成功:", v.sourcePath.substring(v.sourcePath.lastIndexOf("/") + 1, v.sourcePath.length))
})
}
});
function getFolders(dir) {
return fs.readdirSync(dir)
.filter(function (file) {
return fs.statSync(path.join(dir, file)).isDirectory();
});
}
\ No newline at end of file
var fs = require("fs");
// fs.writeFileSync(
// "./released/output.js",
// fs.readFileSync("./output.js")
// )
var endPath = './released/';
fs.writeFileSync(endPath + "output.js",
// 'import * as FYGE from "fyge-tbmini";\n' +
// 'import * as FYGE from "fyge";\n' +//以后改成这个
// 'import * as SvgaParser from "svga-parser";\n' +
fs.readFileSync("./output.js"));
console.log("js生成")
var fs = require('fs');
var path = require('path');
const co = require('co');
const OSS = require('ali-oss');
const chalk = require('chalk');
const ProgressBar = require('progress');
class TuiaAutoUpload {
constructor(props, type) {
this.type = type;
const defaultOptions = {
dir: undefined,
originDir: undefined
}
this.options = Object.assign({}, defaultOptions, props);
if (!this.options.dir || !this.options.originDir) {
console.log(chalk.red('缺少参数,初始化失败'))
return;
}
this.init();
}
init() {
var _this = this;
this.client = new OSS({
region: 'oss-cn-hangzhou',
accessKeyId: 'LTAI4Fw25WcfcGv7FvcHoiHK',
accessKeySecret: 'NZk1NtT9J5HFaAolNbtQdzTzLLvLYm',
bucket: _this.type === 'prod' ? 'duiba' : 'daily-duiba'
});
this.bar = new ProgressBar(chalk.yellow(` 文件上传中 [:bar] :current/${this.files().length} :percent :elapseds`), {
complete: '●',
incomplete: '○',
width: 20,
total: this.files().length,
callback: () => {
console.log(chalk.green('\n All complete.'));
console.log(chalk.blue(`\n 本次队列文件共${this.files().length}个,已存在文件${this.existFiles}个,上传文件${this.uploadFiles}个,上传失败文件${this.errorFiles}个\n`));
}
})
return this;
}
files() {
var _this = this;
if (this._files) return this._files;
this._files = [];
/**
* 文件遍历方法
* @param filePath 需要遍历的文件路径
*/
function fileDisplay(filePath) {
//根据文件路径读取文件,返回文件列表
var files = fs.readdirSync(filePath);
files.forEach(function (filename) {
//获取当前文件的绝对路径
var filedir = path.join(filePath, filename);
//根据文件路径获取文件信息,返回一个fs.Stats对象
var stats = fs.statSync(filedir);
var isFile = stats.isFile();//是文件
var isDir = stats.isDirectory();//是文件夹
if (isFile) {
var sep = '/';
if ('win32' == process.platform)
sep = '\\';
var newDirArr = filedir.split(sep);
newDirArr.shift();
_this._files.push(newDirArr.join('/'));
}
if (isDir) {
fileDisplay(filedir);//递归,如果是文件夹,就继续遍历该文件夹下面的文件
}
});
}
//调用文件遍历方法
fileDisplay(this.options.dir);
return this._files;
}
start() {
this.files().map((file, index) => {
let _this = this;
const path1 = path.join(path.resolve(__dirname, '..'), 'released', file);
let originFile;
this.existFiles = 0;
this.uploadFiles = 0;
this.errorFiles = 0;
co(function* () {
const originPath = `${_this.options.originDir}${file}`;
try {
originFile = yield _this.client.head(originPath);
} catch (error) {
originFile = error;
}
if (_this.type === 'prod') {
if (originFile.status === 404) {
yield _this.client.put(originPath, path1);
_this.uploadFiles += 1;
} else {
_this.existFiles += 1;
}
} else if (_this.type === 'dev') {
if (originFile.status === 404 || originFile.status === 200) {
_this.existFiles += 1;
}
yield _this.client.put(originPath, path1, {
headers: {
'Cache-Control': 'no-cache'
}
})
_this.uploadFiles += 1;
}
_this.bar.tick();
}).catch(function (err) {
_this.errorFiles += 1;
console.log(err);
});
});
}
}
const configFileName = 'project.json';
if (!fs.existsSync(configFileName)) {
throw new Error(`${configFileName}不存在.`)
}
let config = fs.readFileSync('project.json');
config = JSON.parse(config + '');
if (!config.type) {
throw new Error(`${configFileName}的type不存在.`)
}
if (!config.name) {
throw new Error(`${configFileName}的name不存在.`)
}
const now = new Date();
const version = Math.round(now.getTime() / 1000);
console.log(`版本号:
${version}`)
const autoupload = new TuiaAutoUpload({
dir: './released/',
// dir: path.join(__dirname, './released/'),
originDir: `/db_games/${config.type}/${config.name}/${version}/`
}, "prod")
autoupload.start()
var iconv = require('iconv-lite');
var readPath = "./released/resource/";
//读取json文件
var data = iconv.decode(fs.readFileSync(readPath + "res.json"), "utf-8");//GBK
//反序列化
data = JSON.parse(data);
data.path = `https://yun.duiba.com.cn/db_games/${config.type}/${config.name}/${version}/resource/`
//写入目标文件夹,可配置,每个项目必须修改,或者直接和project的保持一致(淘宝项目文件固定后)
var endPath = './src/';
var endFile = `export const ResJson = ${JSON.stringify(data, "", "\t")}`
endFile = endFile.replace(
`"path": "${data.path}"`,
`// eslint-disable-next-line\n\t"path": "${data.path}"`
);
fs.writeFileSync(endPath + "ResJson.ts", endFile);
//根据参数吧,有就是web。需要生成皮肤和js,没有就不执行后续
let arg = process.argv.splice(2);
if (!arg[0]) return;
//有版本号了,模板也生成吧
require("./createHtml")(`${config.type}/${config.name}/${version}`);
var uploadSingleJs = require("./uploadSingleJs")
var exec = require('child_process').exec;
//打包js
exec("webpack --config webpack.prod.js", { encoding: 'utf8' }, (e) => {
if (e) {
console.log('webpack error:', e)
return
}
uploadSingleJs(`${config.type}/${config.name}/${version}`)
//再打印一次
console.log(`版本号:
${version}`)
})
\ No newline at end of file
const co = require('co');
const OSS = require('ali-oss');
var fs = require('fs');
let arg = process.argv.splice(2);
//只打包js时,自执行上传
if(arg[0])uploadSingleJs();
function uploadSingleJs(url) {
if (!url) {//不传的时候
const configFileName = 'project.json';
if (!fs.existsSync(configFileName)) {
throw new Error(`${configFileName}不存在.`)
}
let config = fs.readFileSync('project.json');
config = JSON.parse(config + '');
if (!config.type) {
throw new Error(`${configFileName}的type不存在.`)
}
if (!config.name) {
throw new Error(`${configFileName}的name不存在.`)
}
const now = new Date();
const version = Math.round(now.getTime() / 1000);
console.log(`版本号:
${version}`)
url = `${config.type}/${config.name}/${version}`;
require("./createHtml")(`${config.type}/${config.name}/${version}`);
}
//单js文件上传
co(function* () {
const originPath = `/db_games/${url}/output.js`;
var client = new OSS({
region: 'oss-cn-hangzhou',
accessKeyId: 'LTAI4Fw25WcfcGv7FvcHoiHK',
accessKeySecret: 'NZk1NtT9J5HFaAolNbtQdzTzLLvLYm',
bucket: 'duiba'
})
var originFile;
try {
originFile = yield client.head(originPath);
} catch (error) {
originFile = error;
}
if (originFile.status === 404)
yield client.put(originPath, "./output.js");
})
}
module.exports = uploadSingleJs
\ No newline at end of file
This diff is collapsed.
...@@ -2,6 +2,8 @@ import { KeyBoardStateStore } from './../module/keyboardState/keyboardState'; ...@@ -2,6 +2,8 @@ import { KeyBoardStateStore } from './../module/keyboardState/keyboardState';
import * as THREE from "three"; import * as THREE from "three";
import { EventDispatcher } from "../module/EventDispatcher"; import { EventDispatcher } from "../module/EventDispatcher";
import { GLTFLoader } from '../module/loaders/GLTFLoader'; import { GLTFLoader } from '../module/loaders/GLTFLoader';
import { PreloadGroup } from '../module/UI/PreloadGroup/PreloadGroup';
import { RES } from '../module/RES';
const materialDynamic = new THREE.MeshPhongMaterial( { color:0xfca400 } ); const materialDynamic = new THREE.MeshPhongMaterial( { color:0xfca400 } );
const materialStatic = new THREE.MeshPhongMaterial( { color:0x999999 } ); const materialStatic = new THREE.MeshPhongMaterial( { color:0x999999 } );
...@@ -55,7 +57,7 @@ const VehicleDebugConfig = { ...@@ -55,7 +57,7 @@ const VehicleDebugConfig = {
} }
export class Vehicle extends THREE.Object3D{ export class Vehicle extends PreloadGroup{
chassisMesh: THREE.Group // 车身 chassisMesh: THREE.Group // 车身
fixedChassicMesh: THREE.Group // 固定的车身 fixedChassicMesh: THREE.Group // 固定的车身
wheelMeshes: any[] = [] wheelMeshes: any[] = []
...@@ -103,17 +105,16 @@ export class Vehicle extends THREE.Object3D{ ...@@ -103,17 +105,16 @@ export class Vehicle extends THREE.Object3D{
body.setActivationState(4); body.setActivationState(4);
var chassisMesh = this.chassisMesh = this.createChassisMesh(chassisWidth, chassisHeight, chassisLength); var chassisMesh = this.chassisMesh = this.createChassisMesh(chassisWidth, chassisHeight, chassisLength);
GLTFLoaderIns.setPath('/resource/gltf/').load('qiche_V6.gltf', (gltf: GltfModel) => { const gltf: GltfModel = RES.getRes('qiche_V6.gltf')
chassisMesh.add(gltf.scene) chassisMesh.add(gltf.scene)
gltf.scene.visible = !VehicleDebugConfig.debugger gltf.scene.visible = !VehicleDebugConfig.debugger
gltf.scene.translateY(-1) gltf.scene.translateY(-0.9)
gltf.scene.traverse(function(obj) { gltf.scene.traverse(function(obj) {
// @ts-ignore // @ts-ignore
if (obj.isMesh) { if (obj.isMesh) {
obj.castShadow = true obj.castShadow = true
} }
})
}) })
// this.fixedChassicMesh = this.createChassisMesh(chassisWidth, chassisHeight, chassisLength) // this.fixedChassicMesh = this.createChassisMesh(chassisWidth, chassisHeight, chassisLength)
...@@ -271,7 +272,7 @@ export class Vehicle extends THREE.Object3D{ ...@@ -271,7 +272,7 @@ export class Vehicle extends THREE.Object3D{
addWheel(isFront: boolean, pos: Ammo.btVector3, radius: number, width: number, index: number) { addWheel(isFront: boolean, pos: Ammo.btVector3, radius: number, width: number, index: number) {
const vehicle = this.raycastVehicle const vehicle = this.raycastVehicle
const tuning = this.btVehicleTuning const tuning = this.btVehicleTuning
var friction = 1000; var friction = 10000;
// suspension 暂停 Stiffness刚度 // suspension 暂停 Stiffness刚度
var suspensionStiffness = 20.0; var suspensionStiffness = 20.0;
...@@ -303,7 +304,7 @@ export class Vehicle extends THREE.Object3D{ ...@@ -303,7 +304,7 @@ export class Vehicle extends THREE.Object3D{
this.wheelMeshes[index] = this.createWheelMesh(radius, width); this.wheelMeshes[index] = this.createWheelMesh(radius, width);
} }
createWheelMesh(radius: number, width: number) { createWheelMesh = (radius: number, width: number) => {
const group = new THREE.Group() const group = new THREE.Group()
var t = new THREE.CylinderGeometry(radius, radius, width, 24, 1); var t = new THREE.CylinderGeometry(radius, radius, width, 24, 1);
t.rotateZ(Math.PI / 2); t.rotateZ(Math.PI / 2);
...@@ -355,17 +356,12 @@ export class Vehicle extends THREE.Object3D{ ...@@ -355,17 +356,12 @@ export class Vehicle extends THREE.Object3D{
var wheelWidthFront = 0.2; var wheelWidthFront = 0.2;
const LuntaiIns = this.luntaiIns = await new Promise<GltfModel>(resolve => { const LuntaiIns: GltfModel = this.luntaiIns = RES.getRes('luntai.gltf')
GLTFLoaderIns.setPath('/resource/gltf/').load('luntai.gltf', (ins: GltfModel) => { LuntaiIns.scene.traverse(function(obj) {
// @ts-ignore
ins.scene.traverse(function(obj) { if (obj.isMesh) {
// @ts-ignore obj.castShadow = true
if (obj.isMesh) { }
obj.castShadow = true
}
})
resolve(ins)
})
}) })
this.addWheel(true, new Ammo.btVector3(wheelHalfTrackFront, wheelAxisHeightFront, wheelAxisFrontPosition), wheelRadiusFront, wheelWidthFront, FRONT_LEFT); this.addWheel(true, new Ammo.btVector3(wheelHalfTrackFront, wheelAxisHeightFront, wheelAxisFrontPosition), wheelRadiusFront, wheelWidthFront, FRONT_LEFT);
this.addWheel(true, new Ammo.btVector3(-wheelHalfTrackFront, wheelAxisHeightFront, wheelAxisFrontPosition), wheelRadiusFront, wheelWidthFront, FRONT_RIGHT); this.addWheel(true, new Ammo.btVector3(-wheelHalfTrackFront, wheelAxisHeightFront, wheelAxisFrontPosition), wheelRadiusFront, wheelWidthFront, FRONT_RIGHT);
...@@ -410,23 +406,25 @@ export class Vehicle extends THREE.Object3D{ ...@@ -410,23 +406,25 @@ export class Vehicle extends THREE.Object3D{
const isBreaking = this.actions.braking || KeyBoardStateStore.isPressed('s') const isBreaking = this.actions.braking || KeyBoardStateStore.isPressed('s')
const turnRight = this.actions.right || KeyBoardStateStore.isPressed('d') const turnRight = this.actions.right || KeyBoardStateStore.isPressed('d')
const turnLeft = this.actions.left || KeyBoardStateStore.isPressed('a') const turnLeft = this.actions.left || KeyBoardStateStore.isPressed('a')
let stopFlag = true
if (!isAccelerating && !isBreaking && speed !== 0) {
if (Math.abs(speed) < 0.2) { // if (!isAccelerating && !isBreaking && speed !== 0) {
speed = 0 // if (Math.abs(speed) < 0.2) {
} else { // speed = 0
if (speed > 0) { // } else {
breakingForce = maxBreakingForce / 4; // if (speed > 0) {
} else { // breakingForce = maxBreakingForce / 4;
engineForce = maxEngineForce; // } else {
} // engineForce = maxEngineForce;
} // }
// }
} // }
// 最大速度 // 最大速度
if (speed < 80) { if (speed < 80) {
if (isAccelerating) { if (isAccelerating) {
stopFlag = false
if (speed < -1) { if (speed < -1) {
breakingForce = maxBreakingForce; breakingForce = maxBreakingForce;
} else { } else {
...@@ -434,6 +432,7 @@ export class Vehicle extends THREE.Object3D{ ...@@ -434,6 +432,7 @@ export class Vehicle extends THREE.Object3D{
} }
} }
if (isBreaking) { if (isBreaking) {
stopFlag = false
if (speed > 1) if (speed > 1)
breakingForce = maxBreakingForce; breakingForce = maxBreakingForce;
else engineForce = -maxEngineForce / 2; else engineForce = -maxEngineForce / 2;
...@@ -464,8 +463,8 @@ export class Vehicle extends THREE.Object3D{ ...@@ -464,8 +463,8 @@ export class Vehicle extends THREE.Object3D{
vehicle.applyEngineForce(engineForce, BACK_LEFT); vehicle.applyEngineForce(engineForce, BACK_LEFT);
vehicle.applyEngineForce(engineForce, BACK_RIGHT); vehicle.applyEngineForce(engineForce, BACK_RIGHT);
// brake 刹车 // brake 刹车
vehicle.setBrake(breakingForce / 2, FRONT_LEFT); vehicle.setBrake(stopFlag ? 25 : breakingForce / 2, FRONT_LEFT);
vehicle.setBrake(breakingForce / 2, FRONT_RIGHT); vehicle.setBrake(stopFlag ? 25 : breakingForce / 2, FRONT_RIGHT);
vehicle.setBrake(breakingForce, BACK_LEFT); vehicle.setBrake(breakingForce, BACK_LEFT);
vehicle.setBrake(breakingForce, BACK_RIGHT); vehicle.setBrake(breakingForce, BACK_RIGHT);
......
...@@ -5,20 +5,17 @@ import { ResJson } from "./ResJson" ...@@ -5,20 +5,17 @@ import { ResJson } from "./ResJson"
window['THREE'] = THREE window['THREE'] = THREE
export class StageScene { export class StageScene {
constructor() { constructor(
this.initStage() canvas?: HTMLCanvasElement
) {
this.initStage(canvas)
} }
async initStage() { async initStage(dom?: HTMLCanvasElement) {
RES.loadConfig(ResJson) RES.loadConfig(ResJson)
await RES.loadGroup('skybox')
// @ts-expect-error new CarScene(dom)
Ammo().then(() => {
new CarScene()
})
} }
} }
\ No newline at end of file
new StageScene()
\ No newline at end of file
...@@ -12,6 +12,13 @@ interface DynamicBody { ...@@ -12,6 +12,13 @@ interface DynamicBody {
} }
export class AmmoPhysicWorld { export class AmmoPhysicWorld {
static AmmoPhysicsWorldIns: AmmoPhysicWorld
static getPhysicsWorldIns = (() => {
return () => {
return this.AmmoPhysicsWorldIns || (this.AmmoPhysicsWorldIns = new AmmoPhysicWorld())
}
})()
physicWorld: Ammo.btDiscreteDynamicsWorld physicWorld: Ammo.btDiscreteDynamicsWorld
meshes: THREE.Mesh[] = [] meshes: THREE.Mesh[] = []
meshesMap: WeakMap<THREE.Mesh, Ammo.btRigidBody> = new WeakMap() meshesMap: WeakMap<THREE.Mesh, Ammo.btRigidBody> = new WeakMap()
...@@ -27,6 +34,7 @@ export class AmmoPhysicWorld { ...@@ -27,6 +34,7 @@ export class AmmoPhysicWorld {
rigidBodyList: Ammo.btRigidBody[] = [] rigidBodyList: Ammo.btRigidBody[] = []
constructor() { constructor() {
if (AmmoPhysicWorld.AmmoPhysicsWorldIns) return AmmoPhysicWorld.AmmoPhysicsWorldIns
this.clock = new THREE.Clock(); this.clock = new THREE.Clock();
this.initPhysicWorld() this.initPhysicWorld()
} }
...@@ -40,7 +48,7 @@ export class AmmoPhysicWorld { ...@@ -40,7 +48,7 @@ export class AmmoPhysicWorld {
// 解算器 // 解算器
const solver = new Ammo.btSequentialImpulseConstraintSolver(); const solver = new Ammo.btSequentialImpulseConstraintSolver();
const physicsWorld = this.physicWorld = new Ammo.btDiscreteDynamicsWorld( dispatcher, broadphase, solver, collisionConfiguration ); const physicsWorld = this.physicWorld = new Ammo.btDiscreteDynamicsWorld( dispatcher, broadphase, solver, collisionConfiguration );
physicsWorld.setGravity( new Ammo.btVector3( 0, -9.82, 0 ) ); physicsWorld.setGravity( new Ammo.btVector3( 0, -12.82, 0 ) );
} }
......
export namespace UIViewCtrls {
let LoadingDom: HTMLElement
let timeoutNum: any
function createLoadingContainer() {
const fragment = document.createDocumentFragment()
const container = fragment.appendChild(document.createElement('div'))
container.classList.add('load-container')
container.appendChild(document.createElement('div')).classList.add('boxLoading')
document.body.appendChild(fragment)
return container
}
export function showLoading() {
if (
!LoadingDom
) {
LoadingDom = createLoadingContainer()
}
LoadingDom.style.display = 'block'
}
export function hideLoading(delayTime: number = 0) {
timeoutNum && clearTimeout(timeoutNum)
if (LoadingDom) {
setTimeout(() => {
LoadingDom.style.display = 'none'
}, delayTime)
}
}
}
\ No newline at end of file
...@@ -8,6 +8,7 @@ import { ...@@ -8,6 +8,7 @@ import {
} from 'three' } from 'three'
import { EventDispatcher } from './EventDispatcher'; import { EventDispatcher } from './EventDispatcher';
import { OrbitControls } from './OrbitControls/index'; import { OrbitControls } from './OrbitControls/index';
import { RES } from './RES';
export enum EVENTS_ENUM { export enum EVENTS_ENUM {
ENTERFRAME = 'ENTERFRAME', ENTERFRAME = 'ENTERFRAME',
...@@ -27,7 +28,33 @@ export enum EVENTS_ENUM { ...@@ -27,7 +28,33 @@ export enum EVENTS_ENUM {
// [x in EventsType]?: EventsCall[] // [x in EventsType]?: EventsCall[]
// } // }
export class PerspectiveScene extends EventDispatcher<EVENTS_ENUM> { class ScenePreloadGroup extends EventDispatcher<EVENTS_ENUM> {
get groupNames(): string[] { return null }
constructor(...args: any[]) {
super()
this._preloadRes()
}
_preloadRes() {
new Promise((resolve, reject) => {
if (this.groupNames && this.groupNames.length) {
Promise.all(
this.groupNames.map(name => RES.loadGroup(name))
).then(resolve, reject)
} else {
resolve(1)
}
}).then(() => {
this.ViewDraw()
})
}
protected ViewDraw() {}
}
export class PerspectiveScene extends ScenePreloadGroup {
scene: Scene scene: Scene
camera: PerspectiveCamera camera: PerspectiveCamera
clock: Clock clock: Clock
...@@ -35,8 +62,13 @@ export class PerspectiveScene extends EventDispatcher<EVENTS_ENUM> { ...@@ -35,8 +62,13 @@ export class PerspectiveScene extends EventDispatcher<EVENTS_ENUM> {
rendererDom: HTMLCanvasElement rendererDom: HTMLCanvasElement
OrbitControlsIns: OrbitControls OrbitControlsIns: OrbitControls
constructor() { renderCanvasElement: HTMLCanvasElement
constructor(
canvasDom?: HTMLCanvasElement
) {
super() super()
this.renderCanvasElement = canvasDom
this.clock = new Clock() this.clock = new Clock()
this.__initScene() this.__initScene()
this.__initCamera() this.__initCamera()
...@@ -59,7 +91,7 @@ export class PerspectiveScene extends EventDispatcher<EVENTS_ENUM> { ...@@ -59,7 +91,7 @@ export class PerspectiveScene extends EventDispatcher<EVENTS_ENUM> {
} }
private __initRenderer() { private __initRenderer() {
const matrialSceneCanvas = this.rendererDom = document.createElement('canvas') const matrialSceneCanvas = this.rendererDom = this.renderCanvasElement || document.createElement('canvas')
matrialSceneCanvas.style.display = 'block' matrialSceneCanvas.style.display = 'block'
const _renderer = this.renderer = new WebGLRenderer({ const _renderer = this.renderer = new WebGLRenderer({
canvas: matrialSceneCanvas, // 如果指定了canvas,则不会创建一个新的canvas, canvas: matrialSceneCanvas, // 如果指定了canvas,则不会创建一个新的canvas,
...@@ -68,6 +100,8 @@ export class PerspectiveScene extends EventDispatcher<EVENTS_ENUM> { ...@@ -68,6 +100,8 @@ export class PerspectiveScene extends EventDispatcher<EVENTS_ENUM> {
// _renderer.shadowMap.enabled = true // _renderer.shadowMap.enabled = true
// _renderer.shadowMap.type = PCFShadowMap // _renderer.shadowMap.type = PCFShadowMap
_renderer.setSize(window.innerWidth, window.innerHeight) _renderer.setSize(window.innerWidth, window.innerHeight)
// this.camera.updateProjectionMatrix()
// _renderer.setViewport(0, 0, 812, 375)
_renderer.setPixelRatio(window.devicePixelRatio) _renderer.setPixelRatio(window.devicePixelRatio)
_renderer.outputEncoding = sRGBEncoding; _renderer.outputEncoding = sRGBEncoding;
document.body.appendChild(_renderer.domElement) document.body.appendChild(_renderer.domElement)
...@@ -83,7 +117,7 @@ export class PerspectiveScene extends EventDispatcher<EVENTS_ENUM> { ...@@ -83,7 +117,7 @@ export class PerspectiveScene extends EventDispatcher<EVENTS_ENUM> {
this.frameLoop() this.frameLoop()
window.addEventListener('resize', this.onWindowResize) // window.addEventListener('resize', this.onWindowResize)
} }
/** /**
......
import * as THREE from 'three' import * as THREE from 'three'
import { createImperativePromise, ImperativePromise } from './awesome-promise';
import { GLTFLoader } from './loaders/GLTFLoader'; import { GLTFLoader } from './loaders/GLTFLoader';
// 启用下吧,这里存的是 文件名, Three loader 会存 全路劲 // 启用下吧,这里存的是 文件名, Three loader 会存 全路劲
...@@ -94,7 +95,7 @@ export namespace RES { ...@@ -94,7 +95,7 @@ export namespace RES {
let gltfModalHash: { let gltfModalHash: {
[name: string]: GLTFMODAL [name: string]: GLTFMODAL
} } = {}
/** /**
* 音频的加载 * 音频的加载
...@@ -178,6 +179,119 @@ export namespace RES { ...@@ -178,6 +179,119 @@ export namespace RES {
groupsPromiseHash[name] = p; groupsPromiseHash[name] = p;
return p; return p;
} }
export const loadResourceOnce = (function() {
interface QueueItem {
queue: {
onLoad: Function,
onProgress?: Function,
}[],
data: any // 这里可以 通过 data 字段来判断是否 加载过, 如果是请求的话, 可能就不需要了, 直接 delete loading[url] 就好了
wrapPrevPromise?: ImperativePromise<void>
}
const loading: Record<string, QueueItem> = {}
return function(url: string, onLoad: Function, onProgress: Function, force?: boolean) {
if (!force) {
if (loading[url] && loading[url].data) {
onLoad(true, loading[url].data)
// TODO onProgress
return
}
// 有的话, 说明正在加载中
if (loading[url]) {
loading[url].queue.push({
onLoad,
onProgress
})
return
}
} else {
// cancel之前的 load Promise
loading[url] && loading[url].wrapPrevPromise && loading[url].wrapPrevPromise.cancel()
}
// 否则的话, 就是没有加载
const currItem: QueueItem = loading[url] || (loading[url] = {
queue: [],
data: null,
})
currItem.queue.push({
onLoad,
onProgress
})
const type = url.split('.').pop()
loading[url].wrapPrevPromise = createImperativePromise(
new Promise<{
url: string,
suc: boolean,
data?: any
}>((resolve) => {
if (type == 'png' || type == 'jpg') {
console.log('========load =====', url)
TextureLoaderIns.load(url, (texture) => {
// 赋值 data 表面已经 加载完成
currItem.data = texture
resolve({
url,
suc: true,
data: texture
})
}, (e) => {
for (let i = 0; i < currItem.queue.length; i ++) {
const callback = currItem.queue[i]
if (callback.onProgress) {
callback.onProgress(e)
}
}
}, (error) => {
resolve({
url,
suc: false
})
})
} else if (
type == 'gltf'
) {
GltfLoaderIns.load(
url,
(ins: GLTFMODAL) => {
// 赋值 data 表面已经 加载完成
currItem.data = ins
resolve({
url,
suc: true,
data: ins
})
},
(e: any) => {
for (let i = 0; i < currItem.queue.length; i ++) {
const callback = currItem.queue[i]
if (callback.onProgress) {
callback.onProgress(e)
}
}
},
() => {
resolve({
url,
suc: false
})
}
)
}
}).then((cfg) => {
// 防止 force 的时候,又 重新跑多余的逻辑
while (currItem.queue.length) {
currItem.queue.shift().onLoad(cfg.suc, cfg.data)
}
if (!cfg.suc) {
delete loading[cfg.url]
}
})
)
}
})()
/** /**
* var textue = await RES.getResAsync(str); * var textue = await RES.getResAsync(str);
* @param str 可以是网络图片路径或键值 * @param str 可以是网络图片路径或键值
...@@ -306,6 +420,7 @@ export namespace RES { ...@@ -306,6 +420,7 @@ export namespace RES {
} else if (singleResPromiseHash[str]) { } else if (singleResPromiseHash[str]) {
return returnSingleResPromise(str, comFun, thisObj) return returnSingleResPromise(str, comFun, thisObj)
} else { } else {
var groupName = groupname || hasRes(str);
var src = groupName ? resPath + groupName + "/" + str : str; var src = groupName ? resPath + groupName + "/" + str : str;
singleResPromiseHash[str] = new Promise<void>((resolve, reject) => { singleResPromiseHash[str] = new Promise<void>((resolve, reject) => {
GltfLoaderIns.load( GltfLoaderIns.load(
...@@ -347,7 +462,7 @@ export namespace RES { ...@@ -347,7 +462,7 @@ export namespace RES {
return textureHash[str] || THREE.Cache.get(str) || null; return textureHash[str] || THREE.Cache.get(str) || null;
} }
else if (type == "gltf") { else if (type == "gltf") {
return gltfModalHash || null return gltfModalHash[str] || null
} }
} }
/** /**
...@@ -587,4 +702,5 @@ export namespace RES { ...@@ -587,4 +702,5 @@ export namespace RES {
} }
} }
// @ts-ignore
window['load666'] = RES.loadResourceOnce
export type ResolveCallback<T> = (value: T | PromiseLike<T>) => void
export type RejectCallback = (reason?: any) => void
export type CancelCallback = () => void
export type ImperativePromise<T> = {
promise: Promise<T>
resolve: ResolveCallback<T>
reject: RejectCallback
cancel: CancelCallback
}
/**
* 创建指令shi Promise
* @param promiseArg
* @returns
*/
export function createImperativePromise<T>(promiseArg?: Promise<T> | null | undefined): ImperativePromise<T> {
let resolve: ResolveCallback<T> | null = null
let reject: RejectCallback | null = null
const wrappedPromise = new Promise<T>((_resolve, _reject) => {
resolve = _resolve
reject = _reject
})
promiseArg && promiseArg.then(
val => {
resolve && resolve(val)
},
error => {
reject && reject(error)
}
)
return {
promise: wrappedPromise,
resolve: (value: T | PromiseLike<T>) => {
resolve && resolve(value)
},
reject: (reason?: any) => {
reject && reject(reason)
},
cancel: () => {
resolve = null
reject = null
}
}
}
\ No newline at end of file
...@@ -27,7 +27,8 @@ module.exports = { ...@@ -27,7 +27,8 @@ module.exports = {
extensions: ['.ts', '.js', 'tsx'] extensions: ['.ts', '.js', 'tsx']
}, },
output: { output: {
filename: 'bundle.js', filename: 'output.js',
path: path.resolve(__dirname, './dist'), path: __dirname,
libraryTarget: 'umd'
} }
} }
\ No newline at end of file
const { const merge = require('webpack-merge');
merge
} = require('webpack-merge');
const common = require('./webpack.common.js'); const common = require('./webpack.common.js');
const path = require('path') const path = require('path')
// const webpack = require('webpack'); // const webpack = require('webpack');
...@@ -9,16 +7,7 @@ const path = require('path') ...@@ -9,16 +7,7 @@ const path = require('path')
module.exports = merge(common, { module.exports = merge(common, {
mode: "development", mode: "development",
devtool: 'eval-source-map', devtool: 'eval-source-map'
devServer: {
port: '0.0.0.0',
hot: true,
open: true,
port: 9017,
proxy: {
},
static: '.'
}
// plugins: [ // plugins: [
// new MockWebpackPlugin({ // new MockWebpackPlugin({
// config: mockConfig, // config: mockConfig,
......
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const webpack = require('webpack');
const path = require('path')
module.exports = merge(common, {
mode: "development",//production development
devtool: 'source-map',
plugins: [
]
});
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment