1701 lines
56 KiB
JavaScript
1701 lines
56 KiB
JavaScript
const socket = io({path:base_path + "/socket.io"});
|
||
const myId = Date.now();
|
||
let camera, scene, renderer, clock, controls;
|
||
let dirLight, pointLight;
|
||
var ships = [];
|
||
var fishes = [];
|
||
var birds = [];
|
||
var moving_objects = [];
|
||
var rotor, light_house, palm, man_pers, whale, seagull;
|
||
let geometry;
|
||
let material;
|
||
var island_group = new THREE.Group();
|
||
var border_cube_group = new THREE.Group();
|
||
var delta = 0;
|
||
var colors = ["orange", "blue", "maroon", "olive", "silver", "purple", "lime", "blue", "red", "pink"];
|
||
// 60 fps
|
||
var interval = 1 / 60;
|
||
const raycaster = new THREE.Raycaster();
|
||
const pointer = new THREE.Vector2();
|
||
var partical_material, pointsShader;
|
||
var partical_points = [];
|
||
var collision_distance = 4;
|
||
var mouse_down = false;
|
||
var border_cube = [];
|
||
var active_border_cube, last_selected_border_cube;
|
||
var test = false;
|
||
var tt = 1;
|
||
var manual_drive = false;
|
||
var active_border;
|
||
var border_points = [];
|
||
var prom = [];
|
||
var ship_init = {
|
||
x: -5,
|
||
y: 7,
|
||
angle: 40
|
||
}
|
||
var sea_not_clicked = false;
|
||
init();
|
||
|
||
function init() {
|
||
initScene();
|
||
initMisc();
|
||
|
||
window.addEventListener('keydown', function(event) {
|
||
const key = event.key; // "ArrowRight", "ArrowLeft", "ArrowUp", or "ArrowDown"
|
||
// var object = ships[myId];
|
||
var object = seagull;
|
||
if(key == "ArrowUp"){
|
||
if(!object.before_collision_bezier){
|
||
var t_step = 0.002;
|
||
}
|
||
else{
|
||
var t_step = 0.005;
|
||
}
|
||
object.path += t_step;
|
||
}
|
||
if(key == "ArrowDown"){
|
||
if(!object.before_collision_bezier){
|
||
var t_step = 0.002;
|
||
}
|
||
else{
|
||
var t_step = 0.005;
|
||
}
|
||
object.path -= t_step;
|
||
}
|
||
});
|
||
|
||
window.addEventListener( 'resize', onWindowResize );
|
||
canvas.addEventListener( 'mousedown', function(){mouse_down = true} );
|
||
canvas.addEventListener( 'mousemove', function(){if(!ships[myId].moving_stopped || !active_border_cube) mouse_down = false} );
|
||
canvas.addEventListener( 'mouseup', function(e){if(mouse_down) onPointerClick(e)} );
|
||
|
||
var range = document.querySelector("#range");
|
||
range.addEventListener("input", function(){
|
||
floor.scale.x = 100 / ( 101 - this.value);
|
||
floor.scale.y = 100 / ( 101 - this.value);
|
||
});
|
||
|
||
// window.addEventListener("contextmenu", function(){
|
||
// active_border.splice(-1, 1);
|
||
// border_cube_group.remove( border_cube.splice(-1, 1)[0] );
|
||
// });
|
||
|
||
window.addEventListener( 'pointermove', onPointerMove );
|
||
|
||
map.checked = false;
|
||
collision_edit.checked = false;
|
||
|
||
map.addEventListener( 'click', function(){
|
||
if(canvas2.style.display == "none" || canvas2.style.display == ""){
|
||
canvas2.style.display = "block";
|
||
canvas3.style.display = "block";
|
||
drawMapAndBorders(1);
|
||
}
|
||
else{
|
||
canvas2.style.display = "none";
|
||
canvas3.style.display = "none";
|
||
}
|
||
} );
|
||
|
||
collision_edit.addEventListener( 'click', function(){
|
||
ships[myId].moving_stopped = true;
|
||
test = this.checked;
|
||
drawMapAndBorders(1);
|
||
for(var i = 0; i < border_cube_group.children.length; i++){
|
||
border_cube_group.children[i].visible = this.checked;
|
||
}
|
||
if(!test){
|
||
sheet1.classList.remove("hide");
|
||
sheet2.classList.add("hide");
|
||
lagr_test.disabled = true;
|
||
ships[myId].collision = false;
|
||
ships[myId].position.z = ship_init.y;
|
||
ships[myId].position.x = ship_init.x;
|
||
ships[myId].rotation.y = ship_init.angle / 180 * Math.PI;
|
||
ships[myId].path = 1.1; // при t больше единицы движение по кривой Безье остановится
|
||
ships[myId].path2 = 0;
|
||
}
|
||
else{
|
||
sheet1.classList.add("hide");
|
||
sheet2.classList.remove("hide");
|
||
lagr_test.disabled = false;
|
||
shipLagrInit();
|
||
}
|
||
} );
|
||
}
|
||
|
||
function shipLagrInit(){
|
||
ships[myId].before_collision = false;
|
||
ships[myId].before_collision_bezier = false;
|
||
ships[myId].collision = true;
|
||
ships[myId].border_line_num = 0;
|
||
ships[myId].position.x = active_border[0].x;
|
||
ships[myId].position.z = active_border[0].y;
|
||
ships[myId].path2 = active_border[0].x;
|
||
ships[myId].lagr_direction = 1;
|
||
}
|
||
|
||
lagr_test.addEventListener( 'click', function(){
|
||
shipLagrInit();
|
||
} );
|
||
|
||
border_left.addEventListener( 'click', function(){
|
||
active_border = border_points[1];
|
||
} );
|
||
|
||
border_right.addEventListener( 'click', function(){
|
||
active_border = border_points[0];
|
||
} );
|
||
|
||
function drawLagr(){
|
||
ctx3.clearRect(0, 0, canvas2.width, canvas2.height);
|
||
var angle = getAngle({}, active_border[0].x, active_border[0].y, active_border[0 + 1].x, active_border[0 + 1].y, true).angle;
|
||
var step = 1 * Math.cos(angle);
|
||
var n = 0;
|
||
for(var x = active_border[0].x; x < active_border[active_border.length - 1].x; x+=step){
|
||
for(var i = n + 1; i < active_border.length - 1; i++){
|
||
if(x > active_border[i].x){
|
||
angle = getAngle({}, active_border[i].x, active_border[i].y, active_border[i + 1].x, active_border[i + 1].y, true).angle;
|
||
step = 1 * Math.cos(angle);
|
||
n++;
|
||
}
|
||
}
|
||
var y = lagr(x, active_border);
|
||
ctx3.fillStyle = "red";
|
||
ctx3.fillRect(y*10 + 375, -x*10 + 250, 3,3);
|
||
}
|
||
}
|
||
|
||
function initScene() {
|
||
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 );
|
||
camera.position.set( 0, 15, 35 );
|
||
|
||
scene = new THREE.Scene();
|
||
|
||
pointLight = new THREE.PointLight( 0xDDDDDD, 1, 100 );
|
||
pointLight.name = 'Spot Light';
|
||
pointLight.intensity = 10;
|
||
pointLight.decay = 0.2;
|
||
pointLight.position.set(0, 10, 0);
|
||
pointLight.castShadow = true;
|
||
pointLight.receiveShadow = true;
|
||
scene.add( pointLight );
|
||
}
|
||
|
||
function initMisc() {
|
||
clock = new THREE.Clock();
|
||
window.canvas = document.querySelector('#c');
|
||
renderer = new THREE.WebGLRenderer({canvas, antialias: true});
|
||
renderer.setPixelRatio( window.devicePixelRatio );
|
||
renderer.setSize( window.innerWidth, window.innerHeight );
|
||
updateAll();
|
||
|
||
// Mouse control
|
||
controls = new THREE.OrbitControls( camera, canvas );
|
||
controls.target.set( 0, 2, 0 );
|
||
controls.update();
|
||
}
|
||
|
||
function onWindowResize() {
|
||
|
||
camera.aspect = window.innerWidth / window.innerHeight;
|
||
camera.updateProjectionMatrix();
|
||
|
||
renderer.setSize( window.innerWidth, window.innerHeight );
|
||
|
||
}
|
||
|
||
function collision(obj, test){
|
||
if(obj && obj.position){
|
||
var angle = obj.rotation.y;
|
||
var params = getRadiusCoords(obj.position.x, obj.position.z, 25, angle); // Точка на расстоянии 0.5 от центра объекта — нос корабля, к примеру.
|
||
var obj2 = {x: params.x, y: params.y};
|
||
|
||
for(var k = 0; k <= 1; k++){
|
||
for(var i = 0; i < border_points[k].length - 1; i++){
|
||
if(canvas2.style.display != "none"){
|
||
drawMapAndBorders(i);
|
||
}
|
||
|
||
var obj3 = border_points[k][i];
|
||
var obj4 = border_points[k][i + 1];
|
||
var r = Math.sqrt(Math.pow( obj.position.x - obj3.x , 2) + Math.pow(obj.position.z - obj3.y , 2));
|
||
|
||
if( r <= collision_distance && !obj.lagrange_stopped || test){
|
||
if(!obj.before_collision && !obj.before_collision_bezier && !obj.collision){
|
||
|
||
var intersection = lineIntersection({x: obj.position.x, y: obj.position.z}, {x: obj2.x, y: obj2.y}, obj3, obj4);
|
||
|
||
var x = intersection.x;
|
||
var y = intersection.y;
|
||
|
||
if(obj4.y >= obj3.y){
|
||
var condition = x >= obj3.x && x <= obj4.x && y >= obj3.y && y <= obj4.y;
|
||
}
|
||
else{
|
||
var condition = x >= obj3.x && x <= obj4.x && y >= obj4.y && y <= obj3.y;
|
||
}
|
||
if(condition){
|
||
obj.border_line_angle = getAngle({}, obj3.x, obj3.y, obj4.x, obj4.y, true).angle;
|
||
obj.border_line_num = i;
|
||
ctx3.clearRect(0, 0, canvas2.width, canvas2.height);
|
||
drawCross(x, y, "white", size = 0.5);
|
||
active_border = border_points[k];
|
||
if(!test){
|
||
if(i < border_points[k].length / 2 - 1){
|
||
obj.lagr_direction = -1;
|
||
}
|
||
else{
|
||
obj.lagr_direction = 1;
|
||
}
|
||
obj.path2 = x;
|
||
// obj.lagr_direction = -1;
|
||
// obj.path2 = border_points[k][0].x;
|
||
}
|
||
else{
|
||
obj.path2 = 0;
|
||
}
|
||
return r;
|
||
}
|
||
// else{
|
||
// return false;
|
||
// }
|
||
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
// return false;
|
||
}
|
||
// else{
|
||
// return false;
|
||
// }
|
||
return false;
|
||
}
|
||
|
||
function renderScene() {
|
||
// var object = scene.getObjectByName("Scene");
|
||
if(typeof man_pers != "undefined"){
|
||
if(typeof man_pers.mixer != "undefined" && light_house && light_house.children){
|
||
var light_house_plate = light_house.children[0].children[0].children[0].children[0].children[2].geometry.boundingSphere;
|
||
let x0 = light_house_plate.center.x * light_house.scale.x;
|
||
let y0 = -light_house_plate.center.y * light_house.scale.y;
|
||
|
||
var params = getRadiusCoords(x0, y0, light_house_plate.radius * light_house.scale.x - 1.3, man_pers.angle_for_rotation * Math.PI / 180);
|
||
|
||
x0 = man_pers.position.x;
|
||
y0 = man_pers.position.z;
|
||
|
||
man_pers.position.x = params.x;
|
||
man_pers.position.z = params.y;
|
||
getAngle( man_pers, x0, y0, man_pers.position.x, man_pers.position.z);
|
||
man_pers.rotation.y = man_pers.angle + Math.PI/2;
|
||
man_pers.position.y = 1.9;
|
||
}
|
||
}
|
||
|
||
if(typeof man_pers != "undefined" && man_pers){
|
||
man_pers.angle_for_rotation += man_pers.step;
|
||
if(man_pers.angle_for_rotation > 360){
|
||
man_pers.angle_for_rotation = 0;
|
||
}
|
||
}
|
||
|
||
floor.material.uniforms[ 'time' ].value += 0.1 / 60.0;
|
||
|
||
if(pointsShader){
|
||
pointsShader.uniforms[ 'time' ].value += 0.1 / 60.0;
|
||
}
|
||
|
||
if(window.palmShader && window.palmShader.length >= 1){
|
||
for(var i in palm){
|
||
if(window.palmShader[i]){
|
||
palm[i].angle_for_rotation++;
|
||
window.palmShader[i].uniforms[ 'uTime' ].value = palm[i].angle_for_rotation * Math.PI / 180;
|
||
}
|
||
}
|
||
}
|
||
|
||
for(var k in moving_objects){
|
||
var object = moving_objects[k];
|
||
|
||
if(object && !object.test_stop){
|
||
object.test_stop = 0;
|
||
}
|
||
// if(object && object.test_stop < tt || manual_drive){
|
||
if(object){
|
||
|
||
if(!object.rotation_step){
|
||
object.angle_for_rotation++;
|
||
}
|
||
else{
|
||
object.angle_for_rotation += object.rotation_step;
|
||
}
|
||
|
||
if(object.angle_for_rotation > 360){
|
||
object.angle_for_rotation = 0;
|
||
}
|
||
|
||
object.move(object);
|
||
}
|
||
}
|
||
|
||
if(typeof man_pers != "undefined"){
|
||
glow_sphere.scale.x = Math.cos(man_pers.angle_for_rotation * Math.PI / 180);
|
||
glow_sphere.scale.y = Math.cos(man_pers.angle_for_rotation * Math.PI / 180);
|
||
glow_sphere.scale.z = Math.cos(man_pers.angle_for_rotation * Math.PI / 180);
|
||
|
||
glow_sphere.material.uniforms.viewVector.value = new THREE.Vector3().subVectors( camera.position, new THREE.Vector3(island_group.position.x + glow_sphere.position.x, island_group.position.y + glow_sphere.position.y, island_group.position.z + glow_sphere.position.z));
|
||
}
|
||
|
||
updateParticles();
|
||
|
||
if(border_cube_group.children.length > 0 && test){
|
||
intersectBorderCube();
|
||
}
|
||
|
||
renderer.render( scene, camera );
|
||
|
||
}
|
||
|
||
function render() {
|
||
renderScene();
|
||
}
|
||
|
||
function updateAll() {
|
||
requestAnimationFrame(updateAll);
|
||
delta += clock.getDelta();
|
||
|
||
if (delta > interval) {
|
||
// The draw or time dependent code are here
|
||
render();
|
||
|
||
delta = delta % interval;
|
||
}
|
||
}
|
||
////////////////////////////// Move functions ////////////////////////////////////
|
||
|
||
function fishMove(object, minz = -10, maxz = 0.2){
|
||
|
||
if(object.path == undefined || object.path >= 0.9){
|
||
// alert();
|
||
object.collision = false;
|
||
object.path = 0;
|
||
|
||
var x0 = object.position.x0 = object.position.x;
|
||
var y0 = object.position.y0 = object.position.z;
|
||
var z0 = object.position.z0 = object.position.y;
|
||
|
||
object.step = getRandom(2, 5) / 1000;
|
||
|
||
if(object == whale){
|
||
var random_radius = getRandom(5, 20);
|
||
var random_angle = getRandom(0, Math.PI * 2);
|
||
var random_target = getRadiusCoords(0, 0, random_radius, random_angle);
|
||
object.position.x_end = random_target.x;
|
||
object.position.y_end = random_target.y;
|
||
object.position.z_end = getRandom(maxz, minz);
|
||
}
|
||
else{
|
||
object.position.x_end = getRandom(-20, 20);
|
||
object.position.y_end = getRandom(-20, 20);
|
||
object.position.z_end = getRandom(maxz, minz);
|
||
}
|
||
|
||
var params;
|
||
params = getAngle(object, x0, y0, object.position.x_end, object.position.y_end);
|
||
|
||
object.angle_old = object.rotation.y - Math.PI / 2;
|
||
|
||
var r = object.hipotenuse;
|
||
|
||
params = getRadiusCoords(x0, y0, object.hipotenuse / 10, object.angle_old);
|
||
|
||
params2 = getRadiusCoords(x0, y0, r, object.angle_old + 10 / 180 * Math.PI);
|
||
|
||
object.p = [];
|
||
|
||
if(params.x){
|
||
object.p[0] = {
|
||
x: object.position.x0,
|
||
y: object.position.y0,
|
||
z: object.position.z0,
|
||
}
|
||
object.p[1] = {
|
||
x: params.x,
|
||
y: params.y,
|
||
z: getRandom(maxz, minz)
|
||
}
|
||
object.p[2] = {
|
||
x: params2.x,
|
||
y: params2.y,
|
||
z: getRandom(maxz, minz)
|
||
}
|
||
object.p[3] = {
|
||
x: object.position.x_end,
|
||
y: object.position.y_end,
|
||
z: object.position.z_end,
|
||
}
|
||
}
|
||
}
|
||
|
||
if(object.p || test){
|
||
|
||
if(object == whale){
|
||
object.rotation.z = object.angle_for_rotation / 180 * Math.PI;
|
||
}
|
||
|
||
if( (!object.collision || object.lagrange_stopped) && !test ){
|
||
if(object.path == undefined){
|
||
object.path = 0;
|
||
}
|
||
if(object.path <= 1){
|
||
if(!object.before_collision_bezier){
|
||
var t_step = object.step;
|
||
}
|
||
else{
|
||
var t_step = 0.005;
|
||
}
|
||
if(!manual_drive){
|
||
object.path += t_step - t_step * object.path;
|
||
}
|
||
}
|
||
else{
|
||
object.moving_stopped = true;
|
||
}
|
||
}
|
||
if(!test){
|
||
var t = object.path;
|
||
var p0 = object.p[0];
|
||
var p1 = object.p[1];
|
||
var p2 = object.p[2];
|
||
}
|
||
///////////////////
|
||
|
||
var x0 = object.position.x;
|
||
var y0 = object.position.z;
|
||
var z0 = object.position.y;
|
||
|
||
///////////////////
|
||
if(!object.moving_stopped && t <= 1){
|
||
p0 = object.p[0];
|
||
p1 = object.p[1];
|
||
p2 = object.p[2];
|
||
var p3 = object.p[3];
|
||
var p4 = object.p[4];
|
||
object.position.x = Math.pow(1 - t, 3) * p0.x + 3 * t * Math.pow(1 - t, 2) * p1.x
|
||
+ 3 * Math.pow(t, 2) * (1 - t) * p2.x + Math.pow(t, 3) * p3.x;
|
||
object.position.z = Math.pow(1 - t, 3) * p0.y + 3 * t * Math.pow(1 - t, 2) * p1.y
|
||
+ 3 * Math.pow(t, 2) * (1 - t) * p2.y + Math.pow(t, 3) * p3.y;
|
||
object.position.y = Math.pow(1 - t, 3) * p0.z + 3 * t * Math.pow(1 - t, 2) * p1.z
|
||
+ 3 * Math.pow(t, 2) * (1 - t) * p2.z + Math.pow(t, 3) * p3.z;
|
||
}
|
||
// ctx3.fillRect(whale.position.z*10 + 375, -whale.position.x*10 + 250, 1, 1);
|
||
if(t <= 1){
|
||
getAngle(object, x0, y0, object.position.x, object.position.z);
|
||
if(object.angle){
|
||
object.rotation.y = object.angle + Math.PI / 2;
|
||
}
|
||
}
|
||
if(t >= 1 && object.before_collision_bezier){
|
||
// object.before_collision_bezier = false;
|
||
// object.collision = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
function shipMove(object){
|
||
object.position.y = -0.3 + Math.cos(object.angle_for_rotation / 180 * Math.PI + Math.PI / 2) / 10;
|
||
object.rotation.x = Math.cos(object.angle_for_rotation / 180 * Math.PI) / 5;
|
||
|
||
if(object.p || test){
|
||
|
||
var r = collision(object, test) ;
|
||
// Детекция коллизии
|
||
if( r && !object.before_collision && ! object.before_collision_bezier && !object.collision){
|
||
object.before_collision = true;
|
||
object.angle_for_rotation = 0;
|
||
object.path = 0;
|
||
let x0 = object.position.x0 = object.position.x;
|
||
let y0 = object.position.y0 = object.position.z;
|
||
let params, params2, params3;
|
||
params = getAngle(object, x0, y0, object.position.x_end, object.position.y_end);
|
||
|
||
if(object.rotation.y){
|
||
object.angle_old = object.rotation.y;
|
||
}
|
||
}
|
||
|
||
if( (!object.collision || object.lagrange_stopped) && !test ){
|
||
if(object.path == undefined){
|
||
object.path = 0;
|
||
}
|
||
if(object.path <= 1){
|
||
if(!object.before_collision_bezier){
|
||
var t_step = 0.002;
|
||
}
|
||
else{
|
||
var t_step = 0.005;
|
||
}
|
||
if(!manual_drive){
|
||
object.path += t_step;
|
||
}
|
||
|
||
rotor.rotation.x = object.angle_for_rotation / 180 * Math.PI * 10;
|
||
}
|
||
else{
|
||
object.moving_stopped = true;
|
||
}
|
||
}
|
||
if(!object.moving_stopped){
|
||
rotor.rotation.x = object.angle_for_rotation / 180 * Math.PI * 10;
|
||
}
|
||
|
||
if(!test){
|
||
var t = object.path;
|
||
var p0 = object.p[0];
|
||
var p1 = object.p[1];
|
||
var p2 = object.p[2];
|
||
}
|
||
|
||
///////////////////
|
||
|
||
let x0 = object.position.x;
|
||
let y0 = object.position.z;
|
||
|
||
///////////////////
|
||
|
||
if(object.before_collision){
|
||
object.path = 0;
|
||
|
||
object.position.x0 = object.position.x;
|
||
object.position.y0 = object.position.z;
|
||
|
||
var params, params2;
|
||
params = getAngle(object, x0, y0, object.position.x_end, object.position.y_end);
|
||
|
||
object.angle_old = object.rotation.y;
|
||
|
||
var r = 5;
|
||
|
||
var x_bezier_end = object.path2;
|
||
var y_bezier_end = lagr(object.path2, active_border);
|
||
|
||
// let angle = getAngle({}, x0, y0, x_bezier_end, y_bezier_end, true).angle;
|
||
|
||
params = getRadiusCoords(x0, y0, object.hipotenuse / 10, object.angle_old);
|
||
|
||
var line_num = object.border_line_num;
|
||
if(object.lagr_direction > 0){
|
||
var determ = Math.PI;
|
||
}
|
||
else{
|
||
var determ = Math.PI * 2;
|
||
}
|
||
|
||
params2 = getRadiusCoords(active_border[line_num].x, active_border[line_num].y, r, object.border_line_angle + determ);
|
||
|
||
object.p[0] = {
|
||
x: object.position.x,
|
||
y: object.position.z
|
||
}
|
||
object.p[1] = {
|
||
x: params.x,
|
||
y: params.y
|
||
}
|
||
object.p[2] = {
|
||
x: params2.x,
|
||
y: params2.y
|
||
}
|
||
object.p[3] = {
|
||
x: x_bezier_end,
|
||
y: y_bezier_end
|
||
}
|
||
object.before_collision = false;
|
||
object.before_collision_bezier = true;
|
||
}
|
||
|
||
if(object.collision){
|
||
if(!test){
|
||
var p = object.p;
|
||
}
|
||
else{
|
||
var p = [];
|
||
object.p = [];
|
||
}
|
||
|
||
if(object.path2 != undefined){
|
||
object.path2 += 0.02 * object.lagr_direction;
|
||
}
|
||
|
||
// Окончание продвижения по кривой Лагранжа окончено
|
||
if(object.lagr_direction == 1){
|
||
var condition = object.position.x >= active_border[active_border.length - 1].x;
|
||
}
|
||
else{
|
||
var condition = object.position.x <= active_border[0].x;
|
||
}
|
||
|
||
if(condition){
|
||
object.collision = false;
|
||
object.lagrange_stopped = true;
|
||
object.angle_for_rotation = 0;
|
||
object.path = 0;
|
||
|
||
object.position.x0 = object.position.x;
|
||
object.position.y0 = object.position.z;
|
||
|
||
var params;
|
||
params = getAngle(object, x0, y0, object.position.x_end, object.position.y_end, true);
|
||
|
||
object.angle_old = object.rotation.y;
|
||
|
||
var r = object.hipotenuse;
|
||
|
||
params = getRadiusCoords(x0, y0, object.hipotenuse / 10, object.angle_old);
|
||
params2 = getRadiusCoords(x0, y0, r, object.angle_old + 10 / 180 * Math.PI);
|
||
|
||
object.p[0] = {
|
||
x: object.position.x,
|
||
y: object.position.z
|
||
}
|
||
object.p[1] = {
|
||
x: params.x,
|
||
y: params.y
|
||
}
|
||
object.p[2] = {
|
||
x: params2.x,
|
||
y: params2.y
|
||
}
|
||
object.p[3] = {
|
||
x: object.position.x_end,
|
||
y: object.position.y_end
|
||
}
|
||
}
|
||
|
||
// Движение по кривой Лагранжа
|
||
var x = object.path2;
|
||
var y = lagr(x, active_border); // Лагранж
|
||
|
||
object.position.x = x;
|
||
object.position.z = y;
|
||
}
|
||
else if(!object.moving_stopped && t <= 1){
|
||
p0 = object.p[0];
|
||
p1 = object.p[1];
|
||
p2 = object.p[2];
|
||
var p3 = object.p[3];
|
||
var p4 = object.p[4];
|
||
object.position.x = Math.pow(1 - t, 3) * p0.x + 3 * t * Math.pow(1 - t, 2) * p1.x
|
||
+ 3 * Math.pow(t, 2) * (1 - t) * p2.x + Math.pow(t, 3) * p3.x;
|
||
object.position.z = Math.pow(1 - t, 3) * p0.y + 3 * t * Math.pow(1 - t, 2) * p1.y
|
||
+ 3 * Math.pow(t, 2) * (1 - t) * p2.y + Math.pow(t, 3) * p3.y;
|
||
}
|
||
|
||
// В начале движения по безье бывает какой-то резкий скачок угла по сравнению с предыдущим положением,
|
||
// поэтому первый шаг c приращением t прпускаем
|
||
if(t <= 1 && t > t_step || object.collision){
|
||
getAngle(object, x0, y0, object.position.x, object.position.z);
|
||
if(object.angle){
|
||
object.rotation.y = object.angle;
|
||
if(object.before_collision_bezier){
|
||
// console.log(t); ;
|
||
object.test_stop++;
|
||
}
|
||
}
|
||
}
|
||
if(t >= 1 && object.before_collision_bezier){
|
||
object.before_collision_bezier = false;
|
||
object.collision = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
////////////////////////////// Mathematical functions ////////////////////////////////////
|
||
|
||
function getRadiusCoords(x0, y0, radius, angle){
|
||
var x = x0 + radius * Math.cos(angle);
|
||
var y = y0 - radius * Math.sin(angle);
|
||
return {x: x, y: y, angle: angle}
|
||
}
|
||
|
||
function getAngle(object, x0, y0, x_end, y_end, flag = false){
|
||
var a = y0 - y_end;
|
||
var b = x0 - x_end;
|
||
|
||
var hipotenuse_squared = Math.pow(a, 2) + Math.pow(b, 2);
|
||
|
||
var hipotenuse = object.hipotenuse = Math.sqrt(hipotenuse_squared);
|
||
|
||
var sina = object.sina = a / hipotenuse;
|
||
var cosa = object.cosa = b / hipotenuse;
|
||
|
||
if(!flag){
|
||
if(sina > 0){
|
||
object.angle = Math.PI - Math.acos(cosa);
|
||
}
|
||
else{
|
||
object.angle = Math.PI + Math.acos(cosa);
|
||
}
|
||
}
|
||
else{
|
||
if(sina > 0){
|
||
var angle = Math.PI - Math.acos(cosa);
|
||
}
|
||
else{
|
||
var angle = Math.PI + Math.acos(cosa);
|
||
}
|
||
}
|
||
|
||
return {sin: sina, cos: cosa, angle: angle}
|
||
}
|
||
|
||
function getRandom(min, max) {
|
||
const minCeiled = Math.ceil(min);
|
||
const maxFloored = Math.floor(max);
|
||
return Math.floor(Math.random() * (maxFloored - minCeiled) + minCeiled); // The maximum is exclusive and the minimum is inclusive
|
||
}
|
||
|
||
function lagr(x0, points){
|
||
var y0=0;//значение многочлена в точке y0
|
||
var step;
|
||
for(var i=0;i<points.length;i++)
|
||
{
|
||
step=points[i].y;
|
||
for(var j=0;j<points.length;j++)//считаем множитель при i-ом значении
|
||
{ //сеточной функции
|
||
if(i!=j)
|
||
step=step*(x0-points[j].x)/(points[i].x-points[j].x);
|
||
}
|
||
y0+=step;
|
||
}
|
||
return y0;
|
||
}
|
||
|
||
function lineIntersection(p1, p2, p3, p4){
|
||
var x1 = p1.x;
|
||
var y1 = p1.y;
|
||
var x2 = p2.x;
|
||
var y2 = p2.y;
|
||
var x3 = p3.x;
|
||
var y3 = p3.y;
|
||
var x4 = p4.x;
|
||
var y4 = p4.y;
|
||
|
||
var alpha = ( (x1 - x3) * (y4 - y3) - (y1 - y3) * (x4 - x3) ) /
|
||
( (y2 - y1) * (x4 - x3) - (x2 - x1) * (y4 - y3) );
|
||
|
||
// var beta = ( (x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1) ) /
|
||
// ( (y2 - y1) * (x4 - x3) - (x2 - x1) * (y4 - y3) );
|
||
|
||
var x = x1 + alpha * (x2 - x1);
|
||
var y = y1 + alpha * (y2 - y1);
|
||
|
||
// var x = ( (x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4) ) /
|
||
// ( (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4) );
|
||
// var y = ( (x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4) ) /
|
||
// ( (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4) );
|
||
return {x: x, y: y};
|
||
}
|
||
|
||
/////////////////////////////// Mouse events, 3d objects intersections /////////////////////////////////////////
|
||
|
||
socket.on("coords", (obj)=>{
|
||
if(obj.id != myId){
|
||
var obj2 = ships[obj.id];
|
||
if(obj.x && ships[obj.id]){
|
||
ships[obj.id].rotation.y = obj.angle;
|
||
onPointerClick(undefined, ships[obj.id], {x: obj.x, y: obj.y});
|
||
}
|
||
}
|
||
})
|
||
|
||
socket.on("connect", ()=> {
|
||
socket.on("send_objects", (obj_collection)=>{;
|
||
for(var i in obj_collection){
|
||
var obj = obj_collection[i];
|
||
var obj2 = ships[i];
|
||
if(!obj2){
|
||
obj2 = ships[myId].clone();
|
||
obj2.move = function(object){shipMove(object)};
|
||
obj2.position.z = obj.y0;
|
||
obj2.position.x = obj.x0;
|
||
obj2.rotation.y = obj.angle;
|
||
obj2.angle_for_rotation = 0;
|
||
obj2.rotation.z = 0;
|
||
ships[obj.id] = obj2;
|
||
moving_objects[obj.id] = obj2;
|
||
scene.add(obj2);
|
||
ships[obj.id].getObjectByName("Scene").getObjectByName("ship").material
|
||
= ships[myId].getObjectByName("Scene").getObjectByName("ship").material.clone();
|
||
var color = colors[obj.id.toString().slice(-1)];
|
||
ships[obj.id].getObjectByName("Scene").getObjectByName("ship").material.color.set( color );
|
||
if(obj.x){
|
||
onPointerClick(undefined, ships[obj.id], {x: obj.x, y: obj.y});
|
||
}
|
||
}
|
||
}
|
||
})
|
||
})
|
||
|
||
socket.on("remove", (id) => {
|
||
scene.remove(ships[id]);
|
||
delete ships[id];
|
||
delete moving_objects[id];
|
||
scene.remove(partical_points[id]);
|
||
delete partical_points[id];
|
||
})
|
||
|
||
function onPointerClick(e, object, end_coords) {
|
||
ctx3.clearRect(0, 0, canvas2.width, canvas2.height);
|
||
controls.enableRotate = true;
|
||
if(test){
|
||
intersectBorderCube();
|
||
}
|
||
if(!object){
|
||
var canvasBoundingRect = canvas.getBoundingClientRect();
|
||
var t = canvasBoundingRect;
|
||
pointer.x = (e.clientX - t.left) / t.width * 2 - 1;
|
||
pointer.y = -(e.clientY - t.top) / t.height * 2 + 1;
|
||
|
||
if(scene.getObjectByName("Scene")){
|
||
// scene.getObjectByName("Scene").position.x = pointer.y;
|
||
// scene.getObjectByName("Scene").position.z = pointer.x;
|
||
|
||
scene.getObjectByName("Scene").position.y = -0.3;
|
||
}
|
||
|
||
raycaster.setFromCamera( pointer, camera );
|
||
|
||
var intersects2 = raycaster.intersectObjects( light_house.children[0].children[0].children[0].children[0].children );
|
||
if(intersects2[0]){
|
||
sea_not_clicked = true;
|
||
}
|
||
|
||
var intersects = raycaster.intersectObjects( [floor] );
|
||
|
||
|
||
var object = ships[myId];
|
||
if(intersects[0] && !sea_not_clicked){
|
||
socket.emit("mouseclick", {x0: object.position.x, y0: object.position.z, x: intersects[0].point.x, y: intersects[0].point.z, angle: object.rotation.y, id: myId});
|
||
}
|
||
}
|
||
else{
|
||
var intersects = [{point: {x: end_coords.x, z: end_coords.y}}];
|
||
}
|
||
|
||
if(object && intersects[0] && !sea_not_clicked){
|
||
object.collision = false;
|
||
object.lagrange_stopped = false;
|
||
|
||
object.angle_for_rotation = 0;
|
||
object.path = 0;
|
||
|
||
if(!collision_edit.checked){
|
||
object.moving_stopped = false;
|
||
}
|
||
|
||
var x0 = object.position.x0 = object.position.x;
|
||
var y0 = object.position.y0 = object.position.z;
|
||
|
||
object.position.x_end = intersects[0].point.x;
|
||
object.position.y_end = intersects[0].point.z;
|
||
|
||
var params;
|
||
params = getAngle(object, x0, y0, object.position.x_end, object.position.y_end);
|
||
|
||
object.angle_old = object.rotation.y;
|
||
|
||
var r = object.hipotenuse;
|
||
|
||
params = getRadiusCoords(x0, y0, object.hipotenuse / 10, object.angle_old);
|
||
|
||
params2 = getRadiusCoords(x0, y0, r, object.angle_old + 10 / 180 * Math.PI);
|
||
|
||
object.p = [];
|
||
|
||
if(params.x){
|
||
object.p[0] = {
|
||
x: object.position.x0,
|
||
y: object.position.y0
|
||
}
|
||
object.p[1] = {
|
||
x: params.x,
|
||
y: params.y
|
||
}
|
||
object.p[2] = {
|
||
x: params2.x,
|
||
y: params2.y
|
||
}
|
||
object.p[3] = {
|
||
x: object.position.x_end,
|
||
y: object.position.y_end
|
||
}
|
||
}
|
||
|
||
if(object.moving_stopped && test && !active_border_cube && mouse_down){
|
||
var same;
|
||
for(var i = 0; i < border_cube.length; i++){
|
||
var r = Math.sqrt(Math.pow(border_cube[i].position.x - object.position.x_end , 2) + Math.pow(border_cube[i].position.z - object.position.y_end , 2));
|
||
if(r < 1){
|
||
same = true;
|
||
}
|
||
}
|
||
if(!same){
|
||
// active_border.push({x: object.position.x_end, y: object.position.y_end});
|
||
}
|
||
}
|
||
if(object.moving_stopped){
|
||
drawLagr();
|
||
}
|
||
|
||
if(!test){
|
||
drawCross(object.position.x_end, object.position.y_end, "yellow");
|
||
}
|
||
|
||
mouse_down = false;
|
||
if(test){
|
||
active_border_cube = null;
|
||
if(last_selected_border_cube){
|
||
last_selected_border_cube.material.color.set( 0x00ff00 );
|
||
}
|
||
}
|
||
|
||
}
|
||
sea_not_clicked = false;
|
||
}
|
||
|
||
function onPointerMove(e){
|
||
if(mouse_down && active_border_cube){
|
||
controls.enableRotate = false;
|
||
var object = active_border_cube;
|
||
var canvasBoundingRect = canvas.getBoundingClientRect();
|
||
var t = canvasBoundingRect;
|
||
pointer.x = (e.clientX - t.left) / t.width * 2 - 1, pointer.y = -(e.clientY - t.top) / t.height * 2 + 1;
|
||
|
||
raycaster.setFromCamera( pointer, camera );
|
||
|
||
const intersects = raycaster.intersectObjects( [floor] );
|
||
|
||
if(intersects[0] && active_border[object.border_index]){
|
||
object.position.x = active_border[object.border_index].x = intersects[0].point.x;
|
||
object.position.z = active_border[object.border_index].y = intersects[0].point.z;
|
||
}
|
||
}
|
||
}
|
||
|
||
function intersectBorderCube(){
|
||
raycaster.setFromCamera( pointer, camera );
|
||
|
||
const intersects = raycaster.intersectObjects( border_cube_group.children );
|
||
|
||
for ( let i = 0; i < intersects.length; i ++ ) {
|
||
if(intersects[i].object.material && intersects[i].object.material.color){
|
||
if(intersects[i].object.side == "border_right"){
|
||
active_border = border_points[0];
|
||
border_right.checked = true;
|
||
}
|
||
else{
|
||
active_border = border_points[1];
|
||
border_left.checked = true;
|
||
}
|
||
|
||
if(last_selected_border_cube){
|
||
if(last_selected_border_cube.side == "border_right"){
|
||
last_selected_border_cube.material.color.set( 0x00ff00 );
|
||
}
|
||
else{
|
||
last_selected_border_cube.material.color.set( 0x00ffff );
|
||
}
|
||
}
|
||
|
||
intersects[i].object.material.color.set( 0xff0000 );
|
||
intersects[i].object.material.opacity = .4;
|
||
intersects[i].object.material.shading = THREE.SmoothShading;
|
||
active_border_cube = last_selected_border_cube = intersects[i].object;
|
||
}
|
||
}
|
||
}
|
||
|
||
/////////////////////////////////// Map /////////////////////////////////////
|
||
border_points[0] =
|
||
[
|
||
{
|
||
"x": -1.2113842910829153,
|
||
"y": -10.20368127403675
|
||
},
|
||
{
|
||
"x": -0.3268580714700465,
|
||
"y": -7.666822126687212
|
||
},
|
||
{
|
||
"x": 0.6890313333965716,
|
||
"y": -4.403478523373602
|
||
},
|
||
{
|
||
"x": 2.0357299502829433,
|
||
"y": -1.4867182714845308
|
||
},
|
||
{
|
||
"x": 4.708221202175898,
|
||
"y": 1.003468923747237
|
||
},
|
||
{
|
||
"x": 7.603186470908478,
|
||
"y": 2.0330304558189978
|
||
},
|
||
{
|
||
"x": 9.933313576160806,
|
||
"y": 1.417204576840065
|
||
},
|
||
{
|
||
"x": 11.784359617591125,
|
||
"y": -0.7930962743302238
|
||
}
|
||
]
|
||
active_border = border_points[0];
|
||
border_points[1] = [
|
||
{
|
||
"x": 0.37174050726418856,
|
||
"y": -12.049503723260987
|
||
},
|
||
{
|
||
"x": 1.4611625017149312,
|
||
"y": -11.225539099864234
|
||
},
|
||
{
|
||
"x": 3.5639160342243534,
|
||
"y": -10.928587507175635
|
||
},
|
||
{
|
||
"x": 6.383207738717317,
|
||
"y": -10.026572088951687
|
||
},
|
||
{
|
||
"x": 8.288880726504546,
|
||
"y": -8.838856345464318
|
||
},
|
||
{
|
||
"x": 9.423301438191896,
|
||
"y": -7.014197207129665
|
||
},
|
||
{
|
||
"x": 10.628422053686432,
|
||
"y": -5.119482761193863
|
||
},
|
||
{
|
||
"x": 11.764454365474576,
|
||
"y": -2.9429357450408746
|
||
}
|
||
];
|
||
|
||
var rock_active_border = [];
|
||
|
||
function drawMapAndBorders(num){
|
||
ctx2.clearRect(0, 0, canvas2.width, canvas2.height);
|
||
var x, y, angle;
|
||
|
||
var rock_points = light_house.children[0].children[0].children[0].children[0].children[3].geometry.attributes.position;
|
||
|
||
if(rock_active_border.length == 0){
|
||
for(var i = 0; i < rock_points.count; i+=5){
|
||
if(rock_points.getZ(i) < 0){
|
||
|
||
x = rock_points.getX(i);
|
||
y = rock_points.getY(i);
|
||
|
||
angle = getAngle({}, 0, 0, y, x, true).angle;
|
||
|
||
var r = Math.sqrt(Math.pow(x , 2) + Math.pow(y , 2));
|
||
var params = getRadiusCoords(0, 0, r, angle + island_group.rotation.y + Math.PI / 2);
|
||
|
||
rock_active_border.push({x: params.x, y: params.y});
|
||
}
|
||
}
|
||
}
|
||
for(var i = 0; i < rock_active_border.length; i++){
|
||
x = rock_active_border[i].x * light_house.scale.x + island_group.position.x;
|
||
y = rock_active_border[i].y * light_house.scale.z + island_group.position.z;
|
||
ctx2.fillStyle = "lime";
|
||
ctx2.fillRect(y*10 + 375, -x*10 + 250, 4,4);
|
||
}
|
||
|
||
ctx2.beginPath();
|
||
x = -25;
|
||
y = - x * Math.cos(Math.PI / 2) / Math.sin(Math.PI / 2);
|
||
ctx2.strokeStyle = "red";
|
||
ctx2.moveTo(y*10 + 375, -x*10 + 250);
|
||
x = 25;
|
||
y = - x * Math.cos(Math.PI / 2) / Math.sin(Math.PI / 2);
|
||
ctx2.lineTo(y*10 + 375, -x*10 + 250);
|
||
ctx2.stroke();
|
||
|
||
ctx2.beginPath();
|
||
x = -25;
|
||
y = - x * Math.cos(180 * Math.PI / 180) / Math.sin(180 * Math.PI / 180);
|
||
ctx2.strokeStyle = "yellow";
|
||
ctx2.moveTo(y*10 + 375, -x*10 + 250);
|
||
x = 25;
|
||
y = - x * Math.cos(180 * Math.PI / 180) / Math.sin(180 * Math.PI / 180);
|
||
ctx2.lineTo(y*10 + 375, -x*10 + 250);
|
||
ctx2.stroke();
|
||
|
||
var color = ["yellow", "pink", "white", "lime", "blue", "maroon", "purple"];
|
||
|
||
for(var i = 0; i < active_border.length; i++){
|
||
ctx2.fillStyle = "yellow";
|
||
ctx2.fillRect(active_border[i].y*10 + 375, -active_border[i].x*10 + 250, 5,5);
|
||
|
||
if(!border_cube[i]){
|
||
const w = 0.5;
|
||
const geometry = new THREE.BoxGeometry( w, w, w );
|
||
const material = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
|
||
|
||
border_cube[i] = new THREE.Mesh( geometry, material );
|
||
border_cube[i].position.set(active_border[i].x, w/2, active_border[i].y);
|
||
border_cube[i].name = border_cube + "_" + i;
|
||
border_cube[i].border_index = i;
|
||
border_cube[i].cube_index = i;
|
||
border_cube[i].side = border_right.id;
|
||
if(ships[myId].moving_stopped){
|
||
border_cube[i].visible = true;
|
||
}
|
||
else{
|
||
border_cube[i].visible = false;
|
||
}
|
||
border_cube_group.add( border_cube[i] );
|
||
scene.add( border_cube_group );
|
||
}
|
||
}
|
||
var k = i;
|
||
for(var i = 0; i < border_points[1].length; i++){
|
||
ctx2.fillStyle = "blue";
|
||
ctx2.fillRect(border_points[1][i].y*10 + 375, -border_points[1][i].x*10 + 250, 5,5);
|
||
|
||
if(!border_cube[i + k]){
|
||
const w = 0.5;
|
||
const geometry = new THREE.BoxGeometry( w, w, w );
|
||
const material = new THREE.MeshBasicMaterial( {color: 0x00ffff} );
|
||
|
||
border_cube[i + k] = new THREE.Mesh( geometry, material );
|
||
border_cube[i + k].position.set(border_points[1][i].x, w/2, border_points[1][i].y);
|
||
border_cube[i + k].name = border_cube + "_" + (i + k);
|
||
border_cube[i + k].border_index = i;
|
||
border_cube[i + k].cube_index = i + k;
|
||
border_cube[i + k].side = border_left.id;
|
||
if(ships[myId].moving_stopped){
|
||
border_cube[i + k].visible = true;
|
||
}
|
||
else{
|
||
border_cube[i + k].visible = false;
|
||
}
|
||
border_cube_group.add( border_cube[i + k] );
|
||
scene.add( border_cube_group );
|
||
}
|
||
}
|
||
|
||
ctx2.fillStyle = "red";
|
||
var radius = 6;
|
||
ctx2.beginPath();
|
||
ctx2.arc(island_group.position.z*10 + 375 - radius/2, -island_group.position.x*10 + 250 - radius/2, radius, 0, Math.PI * 2);
|
||
ctx2.fill();
|
||
|
||
|
||
|
||
for(var num2 = 0; num2 < active_border.length - 1; num2+=1){
|
||
var x1, y1, x2, y2;
|
||
|
||
angle = getAngle({}, active_border[num2].y, active_border[num2].x, active_border[num2 + 1].y, active_border[num2 + 1].x, true).angle;
|
||
ctx2.strokeStyle = "yellow";
|
||
|
||
ctx2.beginPath();
|
||
x1 = active_border[num2].x;
|
||
y1 = active_border[num2].y;
|
||
ctx2.moveTo(y1*10 + 375, -x1*10 + 250);
|
||
x2 = active_border[num2 + 1].x;
|
||
y2 = - (x2 - active_border[num2].x) * Math.cos(angle) / Math.sin(angle) + active_border[num2].y;
|
||
ctx2.lineTo(y2*10 + 375, -x2*10 + 250);
|
||
ctx2.stroke();
|
||
}
|
||
ctx2.fillStyle = "white";
|
||
radius = 3;
|
||
ctx2.beginPath();
|
||
ctx2.arc(ships[myId].position.z*10 + 375, -ships[myId].position.x*10 + 250, radius, 0, Math.PI * 2);
|
||
ctx2.fill();
|
||
|
||
angle = Math.PI / 2 - ships[myId].rotation.y;
|
||
ctx2.strokeStyle = "white";
|
||
ctx2.beginPath();
|
||
x = ships[myId].position.x;
|
||
y = - (x - ships[myId].position.x) * Math.cos(angle) / Math.sin(angle) + ships[myId].position.z;
|
||
ctx2.moveTo(y*10 + 375, -x*10 + 250);
|
||
if(angle < 0 && angle > -Math.PI){
|
||
x = -25;
|
||
}
|
||
else{
|
||
x = 25;
|
||
}
|
||
y = - (x - ships[myId].position.x) * Math.cos(angle) / Math.sin(angle) + ships[myId].position.z;
|
||
|
||
ctx2.lineTo(y*10 + 375, -x*10 + 250);
|
||
ctx2.stroke();
|
||
|
||
if(ships[myId].before_collision_bezier){
|
||
ctx3.fillStyle = "yellow";
|
||
}
|
||
else if(ships[myId].collision){
|
||
ctx3.fillStyle = "lightblue";
|
||
}
|
||
else{
|
||
ctx3.fillStyle = "red";
|
||
}
|
||
ctx3.fillRect(ships[myId].position.z*10 + 375, -ships[myId].position.x*10 + 250, 2,2);
|
||
}
|
||
|
||
function drawCross(x0, y0, color, size = 1){
|
||
ctx3.lineWidth = 3;
|
||
var x1, y1, x2, y2;
|
||
var angle = Math.PI / 4;
|
||
ctx3.strokeStyle = color;
|
||
ctx3.beginPath();
|
||
x1 = x0 - size;
|
||
y1 = y0 - size;
|
||
ctx3.moveTo(y1*10 + 375, -x1*10 + 250);
|
||
x2 = x0 + size;
|
||
y2 = y0 + size;
|
||
ctx3.lineTo(y2*10 + 375, -x2*10 + 250);
|
||
ctx3.stroke();
|
||
|
||
var x1, y1, x2, y2;
|
||
var angle = -Math.PI / 4;
|
||
ctx3.strokeStyle = color;
|
||
ctx3.beginPath();
|
||
x1 = x0 - size;
|
||
y1 = y0 + size;
|
||
ctx3.moveTo(y1*10 + 375, -x1*10 + 250);
|
||
x2 = x0 + size;
|
||
y2 = y0 - size;
|
||
ctx3.lineTo(y2*10 + 375, -x2*10 + 250);
|
||
ctx3.stroke();
|
||
}
|
||
//////////////////////////////// Water /////////////////////////////////////////////
|
||
prom[0] = new Promise((resolve, reject) =>{
|
||
|
||
const planeSize = 40; // размер плоскости, которую будем использовать для пола
|
||
var planeGeo = new THREE.PlaneGeometry(planeSize, planeSize, 16, 16); // создаем геометрию для пола — попросту размеры
|
||
|
||
{
|
||
window.floor = new THREE.Water( planeGeo, {
|
||
waterNormals: new THREE.TextureLoader().load(floor_texture, function ( texture ) {
|
||
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
|
||
loading_text.innerHTML += "sea is loaded";
|
||
resolve();
|
||
}),
|
||
alpha: 0.9,
|
||
waterColor: 0x1974d2,
|
||
distortionScale: 0,
|
||
sunDirection: new THREE.Vector3( 0.0, 0.1, -1.0 ).normalize(),
|
||
sunColor: 0xffffff,
|
||
});
|
||
floor.position.set(0, 0, 0);
|
||
floor.rotation.x = Math.PI * -.5; // поворачиваем пол на 90 градусов по X
|
||
floor.rotation.z = Math.PI * -.5;
|
||
floor.receiveShadow = true;
|
||
floor.position.set(0, 0, 0);
|
||
floor.material.transparent = true;
|
||
scene.add(floor); // добавляем пол в сцену
|
||
}
|
||
})
|
||
|
||
|
||
/////////////////////////////// Particles /////////////////////////////////////////
|
||
|
||
{
|
||
partical_material = new THREE.PointsMaterial({
|
||
color: "white",
|
||
map: new THREE.TextureLoader().load(smoke_texture),
|
||
onBeforeCompile: patch => {
|
||
patch.uniforms.time = { value: 0 };
|
||
patch.vertexShader = particle_vertecies;
|
||
patch.fragmentShader = particle_fragments;
|
||
pointsShader = patch;
|
||
}
|
||
})
|
||
}
|
||
function updateParticles(){
|
||
for(var i in ships){
|
||
var object = ships[i];
|
||
var id = i;
|
||
if(object.angle_for_rotation % 10 == 0){
|
||
if(object.path && object.path > 0 && object.path < 1 || object.collision){
|
||
let sizes = [];
|
||
let rots = [];
|
||
let pts = new Array(1000).fill(0).map(p => {
|
||
sizes.push((Math.random() * 0.5 + 0.1) / 3);
|
||
rots.push(Math.random() * Math.PI / 10);
|
||
return new THREE.Vector3().random().subScalar(0.5).multiplyScalar(10)
|
||
});
|
||
if(partical_points[id]){
|
||
scene.remove(partical_points[id]);
|
||
}
|
||
geometry = new THREE.BufferGeometry().setFromPoints(pts);
|
||
geometry.setAttribute("size", new THREE.Float32BufferAttribute(sizes, 1));
|
||
geometry.setAttribute("rots", new THREE.Float32BufferAttribute(rots, 1));
|
||
|
||
partical_points[id] = new THREE.Points(geometry, partical_material);
|
||
partical_points[id].scale.set(0.25, 0.02, 0.1);
|
||
if(object){
|
||
partical_points[id].position.x = object.position.x;
|
||
partical_points[id].position.z = object.position.z;
|
||
partical_points[id].rotation.x = object.rotation.x;
|
||
partical_points[id].rotation.y = object.rotation.y;
|
||
partical_points[id].rotation.z = object.rotation.z;
|
||
}
|
||
|
||
scene.add(partical_points[id]);
|
||
}
|
||
else{
|
||
scene.remove(partical_points[id]);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//////////////////////////////// Models /////////////////////////////////////////////
|
||
const gltfLoader = new GLTFLoader();
|
||
const fbxLoader = new FBXLoader();
|
||
|
||
prom[1] = new Promise((resolve, reject) => {
|
||
gltfLoader.load( ship_model, (gltf) => {
|
||
resolve();
|
||
ships[myId] = gltf.scene;
|
||
rotor = ships[myId].getObjectByName("Scene").getObjectByName("rotor");
|
||
scene.add(ships[myId]);
|
||
// ships[myId].children[0].receiveShadow = true
|
||
// ships[myId].children[0].castShadow = true
|
||
ships[myId].scale.set(0.5, 0.5, 0.5);
|
||
ships[myId].angle_for_rotation = 0;
|
||
ships[myId].position.z = ship_init.y;
|
||
ships[myId].position.x = ship_init.x;
|
||
ships[myId].rotation.y = ship_init.angle / 180 * Math.PI;
|
||
|
||
ships[myId].move = function(object){shipMove(object)};
|
||
|
||
var color = colors[myId.toString().slice(-1)];
|
||
ships[myId].getObjectByName("Scene").getObjectByName("ship").material.color.set( color );
|
||
|
||
moving_objects[myId] = ships[myId];
|
||
|
||
}, (bytes) => { loading_text.innerHTML += " " + "ship model " + Math.floor(bytes.loaded / bytes.total * 100) + "% " + "is loaded"})
|
||
});
|
||
|
||
////////////////////////////////////////////////////////////////////////
|
||
prom[2] = new Promise((resolve, reject) => {
|
||
gltfLoader.load( light_house_model, (gltf) => {
|
||
resolve();
|
||
window.light_house = gltf.scene;
|
||
light_house.name = "Lighthouse";
|
||
light_house.scale.set(0.15, 0.15, 0.15);
|
||
light_house.position.y -= 0.025;
|
||
|
||
const vertexShader = island_vertecies;
|
||
const fragmentShader = island_fragments;
|
||
|
||
var rock = light_house.children[0].children[0].children[0].children[0].children[3];
|
||
rock.material.onBeforeCompile = patch => {
|
||
patch.uniforms.texture1 = {value: 0};
|
||
patch.uniforms.texture2 = {value: 0};
|
||
patch.uniforms.texture3 = {value: 0};
|
||
patch.uniforms.intensity = {value: 0};
|
||
patch.uniforms.pointShadowMap = {value: 0};
|
||
patch.vertexShader= vertexShader;
|
||
|
||
patch.fragmentShader= fragmentShader;
|
||
|
||
window.rockShader = patch;
|
||
var texture1 = new THREE.TextureLoader().load(rock_texture, function ( texture ) {
|
||
var texture2 = new THREE.TextureLoader().load(base_path + "/Rock_color2.png", function ( texture ) {
|
||
var texture3 = new THREE.TextureLoader().load(base_path + "/Rock_color.png", function ( texture ) {
|
||
window.rockShader.uniforms.texture1.value = texture1;
|
||
window.rockShader.uniforms.texture2.value = texture2;
|
||
window.rockShader.uniforms.texture3.value = texture3;
|
||
window.rockShader.uniforms.intensity.value = 25;
|
||
map.click();
|
||
socket.emit("mouseclick", {x0: ships[myId].position.x, y0: ships[myId].position.z, x: undefined, y: undefined, angle: ships[myId].rotation.y, id: myId});
|
||
socket.emit("loaded");
|
||
})
|
||
})
|
||
});
|
||
|
||
|
||
// var img = new Image();
|
||
// img.src = rock_texture;
|
||
// img.onload = function(){createImageBitmap(img).then(function (bitmap) {
|
||
// // light_house.children[0].children[0].children[0].children[0].children[3].material.map.source.data = bitmap;
|
||
// setTimeout(function(){
|
||
// window.rockShader.uniforms[ 'texture2' ].value = { type: 't', value: 0, texture: new THREE.TextureLoader().loaa( rock_texture ) };
|
||
// }, 1000);
|
||
|
||
// })};
|
||
|
||
|
||
};
|
||
palmsSet();
|
||
island_group.add(light_house);
|
||
loading_text.innerHTML += " island texture is loading ";
|
||
}, (bytes) => { loading_text.innerHTML += " " + "light house model " + Math.floor(bytes.loaded / bytes.total * 100) + "% " + "is loaded"})
|
||
});
|
||
////////////////////////////////////////////////////////////////////////
|
||
function palmsSet(){
|
||
prom[3] = new Promise((resolve, reject) =>{
|
||
gltfLoader.load( palm_model, (gltf) => {
|
||
resolve();
|
||
window.palm = [];
|
||
palm[0] = gltf.scene;
|
||
palm[0].name = "Palm";
|
||
|
||
palm[0].scale.set(0.5, 0.5, 0.5);
|
||
palm[0].position.x += 5;
|
||
palm[0].position.z -= 5;
|
||
palm[0].position.y = 0.4;
|
||
palm[0].angle_for_rotation = 0;
|
||
|
||
island_group.add(palm[0]);
|
||
|
||
var rock_points = light_house.children[0].children[0].children[0].children[0].children[3].geometry.attributes.position;
|
||
// light_house.children[0].children[0].children[0].children[0].children[3].receiveShadow = true;
|
||
// light_house.children[0].children[0].children[0].children[0].children[3].castShadow = true;
|
||
var rock_points_geometry = light_house.children[0].children[0].children[0].children[0].children[3].geometry;
|
||
var max = rock_points.count;
|
||
var index = 0;
|
||
palm[0].position.x = rock_points.getX(index) * light_house.scale.x;
|
||
palm[0].position.y = rock_points.getZ(index) * light_house.scale.y;
|
||
palm[0].position.z = -rock_points.getY(index) * light_house.scale.z;
|
||
|
||
for(var i = 1; i < 50; i++){
|
||
palm[i] = palm[0].clone();
|
||
// scene.add(palm[i]);
|
||
island_group.add(palm[i]);
|
||
|
||
index = getRandom(1, max);
|
||
palm[i].position.x = rock_points.getX(index) * light_house.scale.x;
|
||
palm[i].position.y = rock_points.getZ(index) * light_house.scale.y;
|
||
palm[i].position.z = -rock_points.getY(index) * light_house.scale.z;
|
||
|
||
// light_house.children[0].children[0].children[0].children[0].children[2].receiveShadow = true;
|
||
light_house_borders = light_house.children[0].children[0].children[0].children[0].children[2].geometry.boundingBox;
|
||
if(palm[i].position.x < (light_house_borders.max.x + 2) * light_house.scale.x && palm[i].position.x > (light_house_borders.min.x - 2) * light_house.scale.x
|
||
&& palm[i].position.z > -(light_house_borders.max.y + 2) * light_house.scale.z && palm[i].position.z < -(light_house_borders.min.y - 2) * light_house.scale.z){
|
||
var scale_size = 0.2;
|
||
}
|
||
else{
|
||
var scale_size = getRandom(30, 50) / 100;
|
||
}
|
||
palm[i].scale.set(scale_size, scale_size, scale_size);
|
||
palm[i].rotation.y = getRandom(0, 314) / 100;
|
||
palm[i].angle_for_rotation = getRandom(0, 360);
|
||
// palm[i].children[0].children[0].children[0].children[0].children[1].children[1].children[0].material
|
||
// = palm[0].children[0].children[0].children[0].children[0].children[1].children[1].children[0].material.clone();
|
||
}
|
||
|
||
scene.add(island_group);
|
||
island_group.position.x += 6;
|
||
island_group.position.z -= 3;
|
||
|
||
var glass = light_house.getObjectByName("Lighthouse_Glass_0");
|
||
glow_sphere.position.y = glass.geometry.boundingSphere.center.z * light_house.scale.y;
|
||
island_group.add(glow_sphere);
|
||
let x0 = glass.geometry.boundingSphere.center.x * light_house.scale.x;
|
||
let y0 = glass.geometry.boundingSphere.center.y * light_house.scale.y;
|
||
glow_sphere.position.x = x0;
|
||
glow_sphere.position.z = -y0;
|
||
|
||
island_group.rotation.y = -Math.PI / 3;
|
||
|
||
loading_text.style.display= "none";
|
||
|
||
window.palmShader = [];
|
||
|
||
for(let i = 0; i < palm.length; i++){ // let потому что дальше промисс и значение придет, когда цикл отработает
|
||
palm[i].children[0].children[0].children[0].children[0].children[1].children[1].children[0].material.onBeforeCompile = patch => {
|
||
patch.uniforms.uTime = { value: 0 };
|
||
// console.log(patch.vertexShader);
|
||
patch.vertexShader = palm_vertecies;
|
||
// console.log(patch.fragmentShader);
|
||
patch.fragmentShader = palm_fragments;
|
||
window.palmShader[i] = patch;
|
||
};
|
||
}
|
||
}, (bytes) => { loading_text.innerHTML += " " + "palm models " + Math.floor(bytes.loaded / bytes.total * 100) + "% " + "is loaded"})
|
||
});
|
||
}
|
||
////////////////////////////////////////////////////////////////////////
|
||
prom[4] = new Promise((resolve, reject) =>{
|
||
fbxLoader.load( base_path + "/Walking.fbx", (fbx) => {
|
||
resolve();
|
||
const root = fbx;
|
||
root.scale.set(0.0025, 0.0025, 0.0025);
|
||
island_group.add(root);
|
||
|
||
man_pers = fbx;
|
||
man_pers.angle_for_rotation = 0;
|
||
|
||
const animations = man_pers.animations;
|
||
|
||
man_pers.mixer = new THREE.AnimationMixer( man_pers );
|
||
man_pers.step = 0.6;
|
||
man_pers.mixer.timeScale = 1;
|
||
man_pers.clock = new THREE.Clock();
|
||
|
||
const walkAction = man_pers.mixer.clipAction( animations[ 0 ] );
|
||
|
||
walkAction.play();
|
||
|
||
}, (bytes) => { loading_text.innerHTML += " " + "character model " + Math.floor(bytes.loaded / bytes.total * 100) + "% " + "is loaded"})
|
||
})
|
||
////////////////////////////////////////////////////////////////////////
|
||
prom[5] = new Promise((resolve, reject) => {
|
||
fbxLoader.load( base_path + "/blue_whale.fbx", (fbx) => {
|
||
resolve();
|
||
var id = Date.now();
|
||
|
||
whale = moving_objects[id] = fishes[id] = fbx;
|
||
|
||
scene.add(whale);
|
||
|
||
whale.scale.set(0.001, 0.001, 0.001);
|
||
whale.angle_for_rotation = 0;
|
||
whale.rotation_step = 0.1;
|
||
|
||
whale.move = function(object){fishMove(object)};
|
||
|
||
const animations = fbx.animations;
|
||
|
||
whale.mixer = new THREE.AnimationMixer( whale );
|
||
whale.step = 0.002;
|
||
whale.mixer.timeScale = 5;
|
||
whale.clock = new THREE.Clock();
|
||
|
||
const walkAction = whale.mixer.clipAction( animations[ 0 ] );
|
||
|
||
walkAction.play();
|
||
|
||
}, (bytes) => { loading_text.innerHTML += " " + "whale model " + Math.floor(bytes.loaded / bytes.total * 100) + "% " + "is loaded"})
|
||
});
|
||
|
||
////////////////////////////////////////////////////////////////////////
|
||
|
||
prom[6] = new Promise((resolve, reject) => {
|
||
gltfLoader.load( base_path + "/seagull.glb", (gltf) => {
|
||
resolve();
|
||
var id = Date.now();
|
||
|
||
seagull = birds[id] = moving_objects[id] = gltf.scene;
|
||
|
||
scene.add(seagull);
|
||
|
||
var size = 0.05;
|
||
|
||
seagull.scale.set(size, size, size);
|
||
seagull.angle_for_rotation = 0;
|
||
|
||
seagull.move = function(object){fishMove(object, 5, 10)};
|
||
|
||
const animations = gltf.animations;
|
||
|
||
seagull.mixer = new THREE.AnimationMixer( seagull );
|
||
seagull.step = 0.002;
|
||
seagull.mixer.timeScale = 5;
|
||
seagull.clock = new THREE.Clock();
|
||
|
||
var walkAction = seagull.mixer.clipAction( animations[ 0 ] );
|
||
|
||
walkAction.play();
|
||
|
||
for(var i = 0; i <= 2; i++){
|
||
id = Date.now() + "_" + i;
|
||
var bird = birds[id] = moving_objects[id] = SkeletonUtils.clone(seagull);
|
||
scene.add(bird);
|
||
bird.scale.set(size, size, size);
|
||
bird.angle_for_rotation = 0;
|
||
bird.move = function(object){fishMove(object, 5, 10)};
|
||
bird.position.set(getRandom(-20, 20), getRandom(-20, 20), getRandom(-20, 20));
|
||
|
||
bird.mixer = new THREE.AnimationMixer( bird );
|
||
bird.step = 0.002;
|
||
bird.mixer.timeScale = 5;
|
||
bird.clock = new THREE.Clock();
|
||
|
||
walkAction = bird.mixer.clipAction( animations[ 0 ] );
|
||
|
||
walkAction.play();
|
||
|
||
}
|
||
|
||
|
||
}, (bytes) => { loading_text.innerHTML += " " + "seagull model " + Math.floor(bytes.loaded / bytes.total * 100) + "% " + "is loaded"})
|
||
});
|
||
|
||
////////////////////////////////////////////////////////////////////////
|
||
|
||
Promise.all(prom).then((values) => {
|
||
loading_text.style.display= "none";
|
||
renderer.setAnimationLoop( animateAll );
|
||
scene.add( glow_sphere );
|
||
});
|
||
function animateAll() {
|
||
animatePers();
|
||
animateFish();
|
||
animateBird();
|
||
}
|
||
function animatePers() {
|
||
let mixerUpdateDelta = man_pers.clock.getDelta();
|
||
man_pers.mixer.update( mixerUpdateDelta );
|
||
}
|
||
function animateFish() {
|
||
let mixerUpdateDelta = whale.clock.getDelta();
|
||
whale.mixer.update( mixerUpdateDelta );
|
||
}
|
||
function animateBird() {
|
||
for(var i in birds){
|
||
bird = birds[i];
|
||
let mixerUpdateDelta = bird.clock.getDelta();
|
||
bird.mixer.update( mixerUpdateDelta );
|
||
}
|
||
}
|
||
|
||
const geometry2 = new THREE.SphereGeometry( 1, 32, 16 );
|
||
const glow_sphere = new THREE.Mesh( geometry2, new THREE.MeshStandardMaterial() );
|
||
|
||
let glowMaterial = new THREE.ShaderMaterial({
|
||
uniforms: {
|
||
viewVector: {
|
||
type: "v3",
|
||
value: camera.position
|
||
}
|
||
},
|
||
vertexShader: `
|
||
uniform vec3 viewVector;
|
||
varying float intensity;
|
||
void main() {
|
||
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4( position, 1.0 );
|
||
vec3 actual_normal = vec3(modelMatrix * vec4(normal, 0.0));
|
||
intensity = pow( dot(normalize(viewVector), actual_normal), 6.0 );
|
||
}
|
||
`,
|
||
fragmentShader: `
|
||
varying float intensity;
|
||
void main() {
|
||
vec3 glow = vec3(1, 0.8, 0.1) * intensity;
|
||
gl_FragColor = vec4( glow, 1.0 );
|
||
}
|
||
`,
|
||
side: THREE.FrontSide,
|
||
blending: THREE.AdditiveBlending,
|
||
transparent: true
|
||
});
|
||
glow_sphere.material = glowMaterial;
|