我是THREE.js的新手,对物理学的了解很差,但是我仍然想制作足球经理的游戏(从顶视图看),我需要知道球的踢脚尽可能真实
当球碰到边界时,我能够使球朝正确的方向移动和旋转,同时改变运动的位置。
现在我需要处理球的弯曲问题,以及如何使球弯曲,从而使球根据脚的角度弧形移动到顶部和侧面(X / Y)击球
我只想说,我需要知道如何处理两种情况:
您的帮助非常合适。谢谢!
** -我添加了代码以显示到目前为止的内容 -我添加了一张说明我的目标(或此人得分目标)的图像
/*
*
* SET UP MOTION PARAMS
*
*/
var boundries = [40, 24] //indicate where the ball needs to move in mirror position
var completeFieldDistance = boundries[0] * 2;
var fullPower = 1.8; //the power needed to move the ball the enitre field in one kick
var power = null; //will be set when the kick set in depending on the distance
var isKickStop = false; //indicate the renderer weather to stop the kick
var velocityX = null;
var velocityY = null;
//*** this is where i need help! ***
//how can I make the ball move in the Z axis with a nice curv up depending on a given angle
var curv = 15;
var peak = curv;
var velocityZ = 0;
var friction = 0.98;
var gravity = 0.5;
var bounciness = 0.8;
var minVelocity = 0.035; //for when it need to stop the kick rendering
var ballRadius = 3;
var ballCircumference = Math.PI * ballRadius * 2;
var ballVelocity = new THREE.Vector3();
var ballRotationAxis = new THREE.Vector3(0, 1, 0);
//world meshes
var ball = {};
var field = {};
/*
*
* THE KICK HANDLERS
*
*/
function onKick(angleDeg, distance) {
isKickStop = true;
peak = curv;
power = (distance / completeFieldDistance) * fullPower;
velocityX = Math.cos(angleDeg) * power;
velocityY = Math.sin(angleDeg) * power;
velocityZ = peak / (distance / 2);
requestAnimationFrame(function (params) {
isKickStop = false;
animateKick();
})
}
//** THIS IS WHERE I NEED HELP - how do I make the ball move
// render the movements of the ball
var animateKick = function (params) {
if (isKickStop) { return; }
ball.position.x += velocityX;
ball.position.z += velocityZ;
ball.position.y += velocityY;
if (Math.abs(velocityX) < minVelocity && Math.abs(velocityY) < minVelocity) {
ball.position.z = ball.bottom;
isKickStop = true;
console.log("DONE!");
return;
}
if (ball.position.z >= peak) {
ball.position.z = peak;
velocityZ *= -1;
}
if (ball.position.z < ball.bottom) {
peak *= gravity;
velocityZ *= -1;
ball.position.z = ball.bottom;
}
// Figure out the rotation based on the velocity and radius of the ball...
ballVelocity.set(velocityX, velocityY, 0);
ballRotationAxis.set(0, 0, 1).cross(ballVelocity).normalize();
var velocityMag = ballVelocity.length();
var rotationAmount = velocityMag * (Math.PI * 2) / ballCircumference;
ball.rotateOnWorldAxis(ballRotationAxis, rotationAmount);
//reduce velocity due to friction
velocityX *= friction;
velocityY *= friction;
//making sure ball is not outside of its boundries
if (Math.abs(ball.position.x) > boundries[0]) {
velocityX *= -1;
ball.position.x = (ball.position.x < 0) ? boundries[0] * -1 : boundries[0];
}
if (Math.abs(ball.position.y) > boundries[1]) {
velocityY *= -1;
ball.position.y = (ball.position.y < 0) ? boundries[1] * -1 : boundries[1];
}
}
window.onload = (function (params) {
/*
*
* SET UP THE WORLD
*
*/
//set up the ratio
var gWidth = window.innerWidth;
var gHeight = window.innerHeight;
var ratio = gWidth / gHeight;
//set the scene
scene = new THREE.Scene();
scene.background = new THREE.Color(0xeaeaea);
//set the camera
var camera = new THREE.PerspectiveCamera(35, ratio, 0.1, 1000);
camera.position.z = 120;
//set the light
var light = new THREE.SpotLight(0xffffff, 1);
light.castShadow = true;
light.position.set(0, 0, 35);
scene.add(light);
// set the renderer
var renderer = new THREE.WebGLRenderer();
//properties for casting shadow
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setSize(gWidth, gHeight);
document.body.appendChild(renderer.domElement);
/*
*
* ADD MESH TO SCENE
*
*/
// create and add the ball
var geometry = new THREE.SphereGeometry(ballRadius, 8, 8);
//make a checkerboard texture for the ball...
var canv = document.createElement('canvas')
canv.width = canv.height = 256;
var ctx = canv.getContext('2d')
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, 256, 256);
ctx.fillStyle = 'black';
for (var y = 0; y < 16; y++)
for (var x = 0; x < 16; x++)
if ((x & 1) != (y & 1)) ctx.fillRect(x * 16, y * 16, 16, 16);
var ballTex = new THREE.Texture(canv);
ballTex.needsUpdate = true;
var material = new THREE.MeshLambertMaterial({
map: ballTex
});
ball = new THREE.Mesh(geometry, material);
ball.castShadow = true;
ball.receiveShadow = false;
ball.bottom = ballRadius / 2;
scene.add(ball);
// create and add the field
var margin = 20;
var fieldRatio = 105 / 68;
var width = 90;
var height = width / fieldRatio;
var material = new THREE.MeshLambertMaterial({ color: 'green' });
var geometry = new THREE.BoxGeometry(width, height, 1);
field = new THREE.Mesh(geometry, material);
field.receiveShadow = true;
field.position.z = -1;
scene.add(field);
/*
*
* HANDLING EVENTS
*
*/
var domEvents = new THREEx.DomEvents(camera, renderer.domElement);
domEvents.addEventListener(field, 'click', function (e) {
//set points 1 and 2
var p1 = { x: e.intersect.point.x, y: e.intersect.point.y };
var p2 = { x: ball.position.x, y: ball.position.y };
var angleDeg = Math.atan2(p1.y - p2.y, p1.x - p2.x);
var a = p1.x - p2.x;
var b = p1.y - p2.y;
var distance = Math.sqrt(a * a + b * b);
window.onKick(angleDeg, distance);
}, false);
/*
*
* ANIMATION STEP
*
*/
var render = function (params) {
//render kick if it is on the go
if(!isKickStop){
animateKick();
}
//render the page
renderer.render(scene, camera);
requestAnimationFrame(render);
}
render();
})()
body {
padding: 0;
margin: 0;
}
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/96/three.min.js"></script>
<script src="https://www.klika.co.il/scripts/three.events.js"></script>
</head>
<body>
</body>
</html>
答案 0 :(得分:1)
我建立了一个模型对此进行模拟,该模型接受几个参数,即初始速度和角速度,在球上有三个力,重力,空气阻力和马格努斯力。
v0_x = 0; //initial velocity
v0_y = 4;
v0_z = 1;
w_x = 0 * Math.PI; // initial angular velocity
w_y = 2 * Math.PI;
w_z = 0 * Math.PI;
m = 2; //weight
rho = 1.2; // air density
g = 9.8; // gravity
f = 10; //frequency of the rotation of the ball
cl = 1.23; //horizontal tension coefficient
cd = 0.5; //air resistance coefficient
D = 0.22; // diameter of the ball
A = Math.PI * Math.pow((0.5 * D), 2); //cross-sectional area of the ball
t_step = 1 / 60;
b = (1 / 2) * cd * rho * A; //for convenience
c = cl * rho * Math.pow(D, 3) * f; // for convenience
vt_x = v0_x
vt_y = v0_y
vt_z = v0_z
animateKick = function() {
if (ball.position.y < 0) {
return;
}
tmp_1 = c * Math.pow(Math.pow(vt_x, 2) + Math.pow(vt_z, 2) + Math.pow(vt_y, 2), 2)
tmp_2 = (Math.sqrt(Math.pow(w_z * vt_y - w_y * vt_z, 2) + Math.pow(w_y * vt_x - w_x * vt_y, 2) + Math.pow(w_x * vt_z - w_z * vt_x, 2)))
tmp = tmp_1 / tmp_2
Fl_x = tmp * (w_z * vt_y - w_y * vt_z)
Fl_z = tmp * (w_y * vt_x - w_x * vt_y)
Fl_y = tmp * (w_x * vt_z - w_z * vt_y)
//Motion differential equation
a_x = -(b / m) * Math.sqrt((Math.pow(vt_z, 2) + Math.pow(vt_y, 2) + Math.pow(vt_x, 2))) * vt_x + (Fl_x / m)
a_z = -(b / m) * Math.sqrt((Math.pow(vt_z, 2) + Math.pow(vt_y, 2) + Math.pow(vt_x, 2))) * vt_z + (Fl_z / m)
a_y = -g - (b / m) * Math.sqrt((Math.pow(vt_z, 2) + Math.pow(vt_y, 2) + Math.pow(vt_x, 2))) * vt_y + (Fl_y / m)
//use formula : s_t = s_0 + v_0 * t to update the position
ball.position.x = ball.position.x + vt_x * t_step
ball.position.z = ball.position.z + vt_z * t_step
ball.position.y = ball.position.y + vt_y * t_step
//use formula : v_t = a * t to update the velocity
vt_x = vt_x + a_x * t_step
vt_z = vt_z + a_z * t_step
vt_y = vt_y + a_y * t_step
}
window.onload = (function() {
gWidth = window.innerWidth;
gHeight = window.innerHeight;
ratio = gWidth / gHeight;
scene = new THREE.Scene();
scene.background = new THREE.Color(0xeaeaea);
camera = new THREE.PerspectiveCamera(35, ratio, 0.1, 1000);
camera.position.z = -15;
light = new THREE.SpotLight(0xffffff, 1);
light.castShadow = true;
light.position.set(0, 5, -10);
scene.add(light);
renderer = new THREE.WebGLRenderer();
//properties for casting shadow
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setSize(gWidth, gHeight);
document.body.appendChild(renderer.domElement);
geometry = new THREE.SphereGeometry(D, 8, 8);
//make a checkerboard texture for the ball...
canv = document.createElement('canvas')
canv.width = canv.height = 256;
ctx = canv.getContext('2d')
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, 256, 256);
ctx.fillStyle = 'black';
for (y = 0; y < 16; y++)
for (x = 0; x < 16; x++)
if ((x & 1) != (y & 1)) ctx.fillRect(x * 16, y * 16, 16, 16);
ballTex = new THREE.Texture(canv);
ballTex.needsUpdate = true;
material = new THREE.MeshLambertMaterial({
map: ballTex
});
ball = new THREE.Mesh(geometry, material);
ball.castShadow = true;
ball.receiveShadow = false;
ball.bottom = D / 2;
scene.add(ball);
camera.lookAt(ball.position);
plane_geometry = new THREE.PlaneGeometry(20, 100, 32);
plane_material = new THREE.MeshBasicMaterial({
color: 'green',
side: THREE.DoubleSide
});
ground_plane = new THREE.Mesh(plane_geometry, plane_material);
ground_plane.rotation.x = 0.5 * Math.PI
ground_plane.position.y = -1
ground_plane.position.z = 20
scene.add(ground_plane);
render = function(params) {
animateKick();
renderer.render(scene, camera);
requestAnimationFrame(render);
};
render();
})
body {
padding: 0;
margin: 0;
}
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/96/three.min.js"></script>
<script src="https://www.klika.co.il/scripts/three.events.js"></script>
</head>
<body>
</body>
</html>