MackeyK24 Posted August 26, 2017 Share Posted August 26, 2017 Hey guys... Especially you @Deltakosh ... I need your help... I have created a Built-In Character Controller (like the one in unity) that basically controls character movement with full jumping, falling and grounding support. Also allows complete user input control with one toggle 'player.enableInput = true'... I am have trouble with the last line... if the 'Auto-Turning' feature is enabled I want the character to always face the direction of the horizontal and vertical input... Kinda like Unreal Engine Third Person Camera usage... I am using the 'lookAt' function to do that now but it 'Snaps To' that direction... so if you went from left to right it would slap to face the other direction instead of rotating 'a it more slower' to the that direction... I don't see a lookAt speed so I don't know how to handle that... I am still a newbie so I don't know all the 'Translation/Rotation' code I could manually using to achieve the same thing... Anyways... any help on fixing the lookout issue... Again ... would be awesome... Here is my current Character Controller code for your reference, have a look... this is how you will use components in the BabylonJS Toolkit UPDATE New Character Controller Code: /* Babylon Character Movement Controller Component */ /* <reference path="{*path*}/Assets/Babylon/Library/babylon.d.ts" /> */ module BABYLON { export class CharacterController extends BABYLON.MeshComponent { public gravity:number = 0.0; public moveSpeed:number = 6.0; public jumpForce:number = 8.0; public dropForce:number = 20.0; public enableInput:boolean = false; public autoTurning:boolean = false; public rotateSpeed:number = 0.25; public applyGrounding:boolean = true; public keyboardJump:number = BABYLON.UserInputKey.SpaceBar; public buttonJump:number = BABYLON.Xbox360Button.A; public isJumping():boolean { return this._jumping; } public isFalling():boolean { return this._falling; } public isGrounded():boolean { return this._grounded; } public getVelocity():BABYLON.Vector3 { return this.manager.getLinearVelocity(this.mesh); } public getAngular():BABYLON.Vector3 { return this.manager.getAngularVelocity(this.mesh); } public onUpdateInput:(velocity:BABYLON.Vector3, horizontal:number, vertical:number, mousex:number, mousey:number, jumped:boolean)=>void = null; private _jumping:boolean = false; private _falling:boolean = false; private _grounded:boolean = true; private _turnIdentity:boolean = false; private _slerpIndentity:BABYLON.Quaternion = null; private _lookPosition:BABYLON.Vector3 = BABYLON.Vector3.Zero(); private _inputVelocity:BABYLON.Vector3 = BABYLON.Vector3.Zero(); private _movementVelocity:BABYLON.Vector3 = BABYLON.Vector3.Zero(); private _contactThreashold:number = 0.5; public constructor(owner: BABYLON.AbstractMesh, scene: BABYLON.Scene, tick: boolean = true, propertyBag: any = {}) { super(owner, scene, tick, propertyBag); this.gravity = this.scene.gravity.y; this.moveSpeed = this.getProperty("moveSpeed", 6.0); this.jumpForce = this.getProperty("jumpForce", 8.0); this.dropForce = this.getProperty("dropForce", 20.0); this.applyGrounding = this.getProperty("grounding", true); this.enableInput = this.getProperty("enableInput", false); this.autoTurning = this.getProperty("autoTurning", false); this.rotateSpeed = this.getProperty("rotateSpeed", 0.25); this._turnIdentity = false; this._slerpIndentity = BABYLON.Quaternion.Identity(); this._movementVelocity.y = this.gravity; } public move(velocity:BABYLON.Vector3, angular:BABYLON.Vector3 = null, jump:boolean = false):void { this._movementVelocity.x = velocity.x * this.moveSpeed; this._movementVelocity.z = velocity.z * this.moveSpeed; if (jump === true && this._grounded === true && this.jumpForce > 0.0) { this._jumping = true; this._movementVelocity.y = this.jumpForce; this.updateGroundingState(); } // Apply scene gravity with drop force delta if (this._movementVelocity.y > this.gravity) { this._movementVelocity.y -= (this.dropForce * this.manager.deltaTime); if (this._movementVelocity.y < this.gravity) { this._movementVelocity.y = this.gravity; } } // Update current movement velocity with physics this.manager.moveWithPhysics(this.mesh, this._movementVelocity, angular); } protected start():void { this._jumping = false; this._falling = false; this._grounded = true; this.updateGroundingState(); this.onCollisionEvent((collider:BABYLON.AbstractMesh, tag:string) => { if (this.manager.checkCollision(this.mesh, collider, BABYLON.CollisionContact.Bottom, this._contactThreashold) === true) { this._jumping = false; this._movementVelocity.y = this.gravity; this.updateGroundingState(); } }); } protected fixed() :void { var falling:boolean = false; var velocity:BABYLON.Vector3 = this.getVelocity(); if (velocity != null && velocity.y < -0.1) { falling = true; } this._falling = falling; this.updateGroundingState(); // Update user input velocity if (this.enableInput === true) { var horizontal:number = this.manager.getUserInput(BABYLON.UserInputAxis.Horizontal); var vertical:number = this.manager.getUserInput(BABYLON.UserInputAxis.Vertical); var mousex:number = this.manager.getUserInput(BABYLON.UserInputAxis.MouseX); var mousey:number = this.manager.getUserInput(BABYLON.UserInputAxis.MouseY); var jumped:boolean = false; // Apply movement and jumping input if (this._grounded === true) { this._inputVelocity.x = horizontal; this._inputVelocity.z = vertical; jumped = (this.manager.getKeyInput(this.keyboardJump) || this.manager.getButtonInput(this.buttonJump)); } // Update custom movement user input if (this.onUpdateInput != null) { this.onUpdateInput(this._inputVelocity, horizontal, vertical, mousex, mousey, jumped); } // Update avatar position and rotation this.move(this._inputVelocity, null, jumped); if (this.autoTurning === true && (horizontal !== 0.0 || vertical !== 0.0)) { if (this._turnIdentity === false) { this.mesh.rotationQuaternion = BABYLON.Quaternion.Identity(); this._turnIdentity = true; } // Rotate actor to face horizontal and vertical movement direction this._lookPosition.x = -horizontal; this._lookPosition.z = -vertical; var position = this.mesh.position.add(this._lookPosition); this.manager.lookAtPosition(this.mesh, position, this._slerpIndentity, this.rotateSpeed); } } } private updateGroundingState():void { this._grounded = (this.applyGrounding === false || (this._jumping === false && this._falling === false)); } } } Quote Link to comment Share on other sites More sharing options...
MackeyK24 Posted August 26, 2017 Author Share Posted August 26, 2017 To be clear, this is the line I need to fix: this.mesh.lookAt(this.mesh.position.add(new BABYLON.Vector3(-horizontal, 0.0, -vertical))); ... It snaps to direction instead of a more natural rotation... Maybe I shouldn't be using that for this use case... I don't know, I'm still new Quote Link to comment Share on other sites More sharing options...
Virax Posted August 26, 2017 Share Posted August 26, 2017 Hello, The Vector3 class has a Lerp method ! You should try it! It should smooth the transition between the position you're adding https://doc.babylonjs.com/classes/2.5/vector3#static-lerp-start-end-amount-rarr-vector3-classes-2-5-vector3- But do you have a playground example to be more clear ? Quote Link to comment Share on other sites More sharing options...
MackeyK24 Posted August 26, 2017 Author Share Posted August 26, 2017 1 hour ago, Virax said: Hello, The Vector3 class has a Lerp method ! You should try it! It should smooth the transition between the position you're adding https://doc.babylonjs.com/classes/2.5/vector3#static-lerp-start-end-amount-rarr-vector3-classes-2-5-vector3- But do you have a playground example to be more clear ? Cant do playground ... its a toolkit typescript component... but the lookAt like is where I'm talking about.... if you were going to rewrite that 'lookAt' line with a Leap ... How would you do it... Can you pleas write re-write that 'lookAt' line from above to do your leaping to replace look at Quote Link to comment Share on other sites More sharing options...
Aerion Posted August 26, 2017 Share Posted August 26, 2017 Yea, I'd like to see this in JS form with proper terrain slope sliding. I tried to get an answer in my other thread on this, & the people in there are great, they're WONDERFUL people, but it didn't pan out too well. Players shouldn't be able to climb steep > 30 degree inclines. Nor' should they be able to jump the steep incline. And a camera that can slide across the ground and zoom in on the player smoothly when looking up. If you want a Unity Character Controller, this is the way to go about one. Quote Link to comment Share on other sites More sharing options...
adam Posted August 26, 2017 Share Posted August 26, 2017 http://playground.babylonjs.com/#UMQ4UR#2 Wingnut 1 Quote Link to comment Share on other sites More sharing options...
MackeyK24 Posted August 27, 2017 Author Share Posted August 27, 2017 6 hours ago, adam said: http://playground.babylonjs.com/#UMQ4UR#2 Yo @adam Thanks man... thats perfect... But something I just didn't get... I saw the Lerp examples but what I don't understand is how the box.lookAt(sphere.position) get influenced by the slerping: var tempQuat = BABYLON.Quaternion.Identity(); var slerpAmount = .2; box.rotationQuaternion = BABYLON.Quaternion.Identity(); scene.registerBeforeRender(function(){ tempQuat.copyFrom(box.rotationQuaternion); box.lookAt(sphere.position); BABYLON.Quaternion.SlerpToRef(tempQuat, box.rotationQuaternion, slerpAmount, box.rotationQuaternion) }); It looks the SLERP code is some kinda of 'WRAPPER' around the lookAt that ALWAYS applies 'Slerped Rotation' factor to handle the change in rotation from the tempQuat to what it is AFTER the lookAt has changed rotation and kinda of OVERIDE what the lookAt did with an 'EASED' rotation... So we really get the Current rotation and store in tempQuat... Then do the LookAt to update the box rotation (that does not change from before) but after that in the the same frame (so you never immediate see the initial lookAt snapping position) we adjust that rotation using our tempQuat and snapped to LookAt rotations and ease between them... I think... Thats what I was not to sure about... being a newbie at all the actual 3D gaming code and translations and rotations and matrix stuff. Thanks for that snippet ... so I can try to understand why it works and how works Quote Link to comment Share on other sites More sharing options...
MackeyK24 Posted August 27, 2017 Author Share Posted August 27, 2017 Yo @adam That is working perfectly... So much so I created a helper function on my unity like scene manager API to handle look at position wit option rotation slerping: /** Rotates owner to look at the vector position and optionally apply slerping to the rotation * * To use slerping the owner mesh rotation should be set to identity before loop * Example: owner.rotationQuaternion = BABYLON.Quaternion.Identity(); * * The slerpIdentity is a temp reference holder for the current owner rotation * Example: var slerpIdentity = BABYLON.Quaternion.Identity(); * * The slerpAmount control the amouts of slerping applied to rotation. default 0.25 */ public lookAtPosition(owner: BABYLON.AbstractMesh, position:BABYLON.Vector3, slerpIdentity:BABYLON.Quaternion = null, slerpAmount:number = 0.25):BABYLON.AbstractMesh { if (slerpIdentity != null && slerpAmount > 0.0) slerpIdentity.copyFrom(owner.rotationQuaternion); var result:BABYLON.AbstractMesh = owner.lookAt(position); if (slerpIdentity != null && slerpAmount > 0.0) BABYLON.Quaternion.SlerpToRef(slerpIdentity, owner.rotationQuaternion, slerpAmount, owner.rotationQuaternion) return result; } Then in my character controller update loop: // Rotate actor to face horizontal and vertical movement direction this._lookPosition.x = -horizontal; this._lookPosition.z = -vertical; var position = this.mesh.position.add(this._lookPosition); this.manager.lookAtPosition(this.mesh, position, this._slerpIndentity, this.rotateSpeed); Thanks again bro... very much adam 1 Quote Link to comment Share on other sites More sharing options...
MackeyK24 Posted August 27, 2017 Author Share Posted August 27, 2017 8 hours ago, Mythros said: Yea, I'd like to see this in JS form with proper terrain slope sliding. I tried to get an answer in my other thread on this, & the people in there are great, they're WONDERFUL people, but it didn't pan out too well. Players shouldn't be able to climb steep > 30 degree inclines. Nor' should they be able to jump the steep incline. And a camera that can slide across the ground and zoom in on the player smoothly when looking up. If you want a Unity Character Controller, this is the way to go about one. Sup @Mythros ... Thanks for the response I would imagine this would deal with more the Physics Imposter setup ... Plus you could always (in the toolkit scene component life-cycle) compensate the character position and velocity (and even utilize the underlying physics imposter to calculate at what angle you are colliding with)... I do this in onCollisionEvent to check whether after a jump or any collision really, if the source collision 'normal axis' is pointing with a certain 'threshold'... So you could augment the physics and help is out to provide this 'Sloping' issues.... BTW... Using my toolkit for unity... If I create a terrain that has heavy sloped hills and I move around with collision... I can just run up... it slides back down just fine... now I'm not sure exactly what property in Babylon and or the physics engine controls that... But seems to work just fine on the Terrain Meshes that I create in the toolkit and use as a ground mesh in Babylon: var canJump = false; var contactNormal = new CANNON.Vec3(); // Normal in the contact, pointing *out* of whatever the player touched var upAxis = new CANNON.Vec3(0,1,0); cannonBody.addEventListener("collide",function(e){ var contact = e.contact; // contact.bi and contact.bj are the colliding bodies, and contact.ni is the collision normal. // We do not yet know which one is which! Let's check. if(contact.bi.id == cannonBody.id) // bi is the player body, flip the contact normal contact.ni.negate(contactNormal); else contactNormal.copy(contact.ni); // bi is something else. Keep the normal as it is // If contactNormal.dot(upAxis) is between 0 and 1, we know that the contact normal is somewhat in the up direction. if(contactNormal.dot(upAxis) > 0.5) // Use a "good" threshold value between 0 and 1 here! canJump = true; }); If that helps any Quote Link to comment Share on other sites More sharing options...
MackeyK24 Posted August 27, 2017 Author Share Posted August 27, 2017 22 hours ago, Mythros said: If you want a Unity Character Controller, this is the way to go about one. BTW... My toolkit always uses the phrase 'Unity-Like' ... So I am actually implementing from scratch using the BabylonJS API every feature in the the toolkit... there is never a UNITY content or script that gets exported... Just the Toolkit Script Components that use WHATEVER logic you put and the built in components that the toolkit internally supports... Just to clarify the phrase 'Unity-Like' Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.