123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- window.THREE = require('three')
- import {Vector3} from 'three'
- import {Main} from './main'
- import {iterateGeometries, createHullShape} from 'three-to-ammo'
- import {sphere_radius_by_volume, consensus_float} from './util'
- import nipplejs from 'nipplejs'
- function staticRaycast(origin, dir){
- var raycaster = new THREE.Raycaster(origin, dir, 0, 1000)
- var hits = raycaster.intersectObjects(Main.scene.children, true)
- for (let index = 0; index < hits.length; index++) {
- if (hits[index].object.userData.static){
- return hits[index]
- }
- }
- }
- window.addEventListener("gamepadconnected", function(e) {
- var gp = navigator.getGamepads()[e.gamepad.index];
- window.gamepad_index = e.gamepad.index
- console.log("Gamepad connected at index %d: %s. %d buttons, %d axes.",
- gp.index, gp.id,
- gp.buttons.length, gp.axes.length);
- });
- window.addEventListener("load", function(e){
- window.left_touch = nipplejs.create({
- zone: document.querySelector(".left")
- })
- window.right_touch = nipplejs.create({
- zone: document.querySelector(".right")
- })
- })
- export class Player {
- constructor(animations) {
- this.ball = Main.scene.getObjectByName("ball_collider")
- this.ball_display = Main.scene.getObjectByName("ball_display")
- this.prince = Main.scene.getObjectByName("prince_armature")
- this.sun = Main.scene.getObjectByName("sun")
- this.animations = {}
- this.ball_radius = 2
- this.heading = new Vector3(0,0,1)
- this.last_position = new Vector3(0,0,0)
- this.strafe_left = 0
- this.strafe_right = 0
- this.volume = 29.26
- this.ball.material.visible = false
- var bdscale_ratio = this.ball_display.scale.x / this.ball.scale.x
- this.ball_display.parent = this.ball
- this.ball_display.position.copy(new Vector3(0,0,0))
- this.ball_display.scale.set(bdscale_ratio,bdscale_ratio,bdscale_ratio)
- this.ball.userData.physicsBody.setFriction( 10 );
- this.ball.userData.physicsBody.setDamping(0.1, 0.2)
- this.ball.onCollide = this.on_collide.bind(this)
- // var skeleton = new THREE.SkeletonHelper( prince );
- // skeleton.visible = true;
- // Main.scene.add( skeleton );
- this.mixer = new THREE.AnimationMixer( this.prince );
- animations.forEach(o => {
- var anim = this.mixer.clipAction(o)
- this.animations[o.name] = anim
- anim.setEffectiveTimeScale(1)
- anim.setEffectiveWeight(0)
- anim.play()
- });
-
-
- }
- rebuild_shell(){
- this.ball_radius = sphere_radius_by_volume(this.volume)
- var raycaster = new THREE.Raycaster()
- var ball = this.ball
- var position_buffer = ball.geometry.attributes.position
- var rebuild = false
- for (let index = 0; index < position_buffer.count; index++) {
- var position = new Vector3(
- position_buffer.array[index*3],
- position_buffer.array[index*3+1],
- position_buffer.array[index*3+2])
-
- // need to set the magnitude of the position to the ball_radius
- position = ball.localToWorld(position.multiply(new THREE.Vector3(30,30,30)))
- var direction = ball.position.clone().sub(position).normalize()
- raycaster.set(position, direction)
- raycaster.far = ball.position.distanceTo(position)
- var intersects = raycaster.intersectObjects(ball.children)
- if (intersects[0] && intersects[0].object != ball){
- //gizmos.line(intersects[0].point, ball.position, 0xff00ff)
- var point = ball.worldToLocal(intersects[0].point)
- // here we make sure the bump does not get out of controll
- // it should:
- // be the min of the cast point and the distance of the hit object center
- // be a max of 1.5 the ball radius
- //normalize point and mult as the distance of the hit object to the ball
- var len = Math.min(
- point.length(),
- this.ball_radius*1.1,
- (ball.position.distanceTo(intersects[0].object.position)))
-
- point.normalize().multiplyScalar(len)
- position_buffer.array[index*3] = point.x
- position_buffer.array[index*3+1] = point.y
- position_buffer.array[index*3+2] = point.z
- position_buffer.needsUpdate = true
- rebuild = true
- }
- // make sure every vertex is as far away as the ball's new radius
- var position = new Vector3(
- position_buffer.array[index*3],
- position_buffer.array[index*3+1],
- position_buffer.array[index*3+2])
- if (position.length() < player.ball_radius){
- rebuild = true
- position.normalize().multiplyScalar(player.ball_radius)
- position_buffer.array[index*3] = position.x
- position_buffer.array[index*3+1] = position.y
- position_buffer.array[index*3+2] = position.z
- }
- }
- if (rebuild){
- const matrixWorld = new THREE.Matrix4();
- var vertices = [];
- var matrices = [];
- var indexes = [];
- var temp = ball.children
- ball.children = []
- iterateGeometries(ball, {}, (vertexArray, matrixArray, indexArray) => {
- vertices.push(vertexArray);
- matrices.push(matrixArray);
- indexes.push(indexArray);
- });
- ball.children = temp
- var shape = createHullShape(vertices, matrices, matrixWorld.elements)
- shape.setLocalScaling(new Ammo.btVector3(ball.scale.x, ball.scale.y, ball.scale.z))
- ball.userData.physicsBody.setCollisionShape(shape)
- }
- }
- on_collide(object, manifold){
- if (!object.userData.static
- && object.userData.physicsBody
- && (object.userData.volume < this.volume*0.3)){
- this.volume += object.userData.volume
- var shape = object.userData.physicsBody.getCollisionShape()
- this.ball.attach(object)
- Main.removeRigidBody(object)
- var rebuild = this.rebuild_shell.bind(this)
- setTimeout(function(){rebuild()}, 1)
- }
- }
- update(dt){
- var body = this.ball.userData.physicsBody
- var ballforce = 200
-
- var axis_LH = 0
- var axis_LV = 0
- var axis_RH = 0
- var axis_RV = 0
- // 65 73
- // 87 68 83 74 75 76
- if (74 in Main.pressed_keys) { axis_RH = -1 }
- if (76 in Main.pressed_keys) { axis_RH = 1 }
- if (73 in Main.pressed_keys) { axis_RV = 1 }
- if (75 in Main.pressed_keys) { axis_RV = -1 }
- if (65 in Main.pressed_keys) { axis_LH = -1 }
- if (68 in Main.pressed_keys) { axis_LH = 1 }
- if (87 in Main.pressed_keys) { axis_LV = 1 }
- if (83 in Main.pressed_keys) { axis_LV = -1 }
- if (window.gamepad_index != undefined){
- var gp = navigator.getGamepads()[window.gamepad_index]
- gp.buttons.forEach(b => {
- if (b.pressed){
- }
- })
- axis_LH = gp.axes[0]
- axis_LV = -gp.axes[1]
- axis_RH = gp.axes[2]
- axis_RV = -gp.axes[3]
- }
- if (left_touch.ids.length > 0){
- var stick = left_touch.get(left_touch.ids[0])
- axis_LV = -(stick.frontPosition.y / 50)
- axis_LH = (stick.frontPosition.x / 50)
- }
- if (right_touch.ids.length > 0){
- var stick = right_touch.get(right_touch.ids[0])
- axis_RV = -(stick.frontPosition.y / 50)
- axis_RH = (stick.frontPosition.x / 50)
- }
- // both sticks need to be engaged for any force to transfer (hence min)
- var v = ballforce * consensus_float(axis_RV, axis_LV)
- body.applyForce(new Ammo.btVector3(this.heading.x*-v, 0, this.heading.z*-v))
- var lateral_heading = player.heading.clone().applyEuler(new THREE.Euler(0, 90, 0))
- var h = ballforce * consensus_float(axis_RH, axis_LH)
- body.applyForce(new Ammo.btVector3(lateral_heading.x*h, 0, lateral_heading.z*h))
- // tank tread style turning
- var turn = axis_RV - axis_LV
- if (Math.abs(turn) > 1) {
- this.heading.applyEuler(new THREE.Euler(0, turn*dt, 0))
- }
-
-
- //body.applyForce(new Ammo.btVector3(0, -50, 0))
- /* var velocity = new Vector3(
- this.ball.userData.physicsBody.getLinearVelocity().x(),
- this.ball.userData.physicsBody.getLinearVelocity().y(),
- this.ball.userData.physicsBody.getLinearVelocity().z()
- ) */
-
- var velocity = player.ball.position.clone().sub(this.last_position.clone())
- var prince_frame_velocity = player.prince.worldToLocal(velocity.clone().add(player.prince.position))
- //window.gizmos.line(this.ball.position, prince_frame_velocity.clone().multiplyScalar(50).add(this.ball.position) )
- //window.gizmos.sphere(this.ball.position.clone().add(velocity.clone().multiplyScalar(10)), 0.2, 0xFF0000)
-
- this.sun.position.copy(new Vector3(4, 51, -33).add(this.ball.position))
- var pp = this.ball.position.clone().add(this.heading.clone().multiplyScalar(5))
- var hit = staticRaycast(pp, new Vector3(0, -1, 0))
- if (hit){
- this.prince.position.lerp(hit.point, 0.5)
- //gizmos.sphere(hit.point, 0.2, 0xFF0000)
- }
- this.prince.lookAt(new Vector3(this.ball.position.x, this.prince.position.y, this.ball.position.z))
- this.prince.rotateY(3.14159)
- var point = this.ball.position.clone().add(this.heading.clone().multiplyScalar(15 + (this.ball_radius*2) ).add(new Vector3(0, 10, 0)))
- Main.camera.position.lerp(point, 0.2)
- Main.camera.lookAt(this.ball.position)
- var forward_vel = prince_frame_velocity.z*-5
- this.animations["push"].setEffectiveWeight(forward_vel)
- this.animations["pull"].setEffectiveWeight(-forward_vel)
- this.animations["idle"].setEffectiveWeight(1-Math.abs(forward_vel))
- this.animations["idle"].setEffectiveTimeScale(0.1)
- this.animations["push"].setEffectiveTimeScale(forward_vel*1.5)
- this.animations["pull"].setEffectiveTimeScale(forward_vel*1.5)
-
- if (consensus_float(axis_RH, axis_LH) < -0.2 || turn > 1){
- this.strafe_left = Math.min(1, this.strafe_left + 0.1)
- }
- if (consensus_float(axis_RH, axis_LH) > 0.2 || turn < -1){
- this.strafe_right = Math.min(1, this.strafe_right + 0.1)
- }
- this.animations["strafe"].setEffectiveWeight(this.strafe_left + this.strafe_right)
- this.animations["strafe"].setEffectiveTimeScale((this.strafe_left + -this.strafe_right)*4)
- this.strafe_left *= 0.9
- this.strafe_right *= 0.9
- this.mixer.update(dt)
- this.last_position = player.ball.position.clone()
- }
- }
|