Page 1 of 1

Need advice in several issues

Posted: Sun Jun 24, 2018 8:46 pm
by KakCAT
Hi,

I'm trying to integrate physics to a jRPG and I'm having a hard time with NPCs because I have no real experience when it comes to physics integration. My main problem is that I have several NPC behaviours and I don't know what's the best approach physics-wise to implement. I've been playing and testing for some days but I need some tips.


Right now "player" is CharacterControllerInput from BEPUphysicsDemos.AlternateMovement slightly tweaked (changed input and camera funcs)


The possible NPC behaviours are:


a) NPCs moving by his own:
1 - Roaming NPC. Walks randomly. Can be pushed by player, cannot push player (but must not go through player)
2 - Path following NPC. Walks a predefined path. Can push player, cannot be pushed by player (but must not go through player)
3 - "Cutscene" NPC. Movement controlled by script. Must go through everything (in order to obey the script) while respecting terrain + stairs.

b) NPCs not moving by his own:
4 - Static NPC. Stays at a place. Unmovable by anything.
5 - "Physics" NPC. Obey physics laws.
6 - "Physics" NPC. Like 5 with locked axis (i.e. crates which can't rotate in the Y axis)


All NPCs should respect the terrain and go up/down stairs.



So far, I've done (or I know how to do):

* I've tagged all collidable/walkable-over objects with a group (A), and all NPCs with another group.


a) NPCs moving by his own:
1 - ??
2 - ??
3 - NPC is CharacterControllerInput. Disable collisions between NPC group, but allow all other collisions during cutscenes.

b) NPCs not moving by his own:
4 - Easy, a normal static bepu Entity, "no mass".
5 - Using Entity too (box, cylinder, convex hull) but with a mass.
6 - As 5, but with LocalInertiaTensorInverse. 0 to no rotation at all, no idea to lock Y rotation only but almost sure it can be achieved putting the correct values into LocalInertiaTensorInverse



And I think 1 and 2 can be achieved as CharacterControllerInput too, but handling collision events somehow. But I don't know if this (or any of
the 6 NPC types) are the easiest way to achieve it.


There's a final consideration which I don't know if this should go in a separate thread or if the consideration makes change some of the answers for some NPC types. CharacterCollider uses a Cylinder, but some NPC shapes should be something other than a Cylinder.

There are two reasons for that:
1-When approaching somebody to talk, cylinder against cylinder is pretty annoying because the player "slides" arround the NPC. When using a box instead (I'm using that in type 4 NPCs) the interaction is very natural.
2-Some NPCs are dogs or people mounting a moving horse. I could approximate a dog with a cylinder because it's small, but the horse is unlikely to give good results.



Sorry for the extensive post and thanks a lot for your time.

Re: Need advice in several issues

Posted: Mon Jun 25, 2018 10:50 pm
by Norbo
For 3-6, the stated options are probably the easiest options. For 1 and 2:
1 - Roaming NPC. Walks randomly. Can be pushed by player, cannot push player (but must not go through player)
Two options: player is kinematic and the NPC is dynamic, or the NPC's interaction is nonphysically controlled.
2 - Path following NPC. Walks a predefined path. Can push player, cannot be pushed by player (but must not go through player)
Two options: the NPC is kinematic and the player is dynamic, or the NPC's interaction is nonphysically controlled.

Given the contradictory requirements, these two will likely be most easily handled with nonphysical control. That would look something like disabling constraint generation using collision rules, then checking for any detected collisions and applying corrective impulses (or even displacements). Note that the character controller uses constraints to move around, so applying a single impulse per frame will tend to 'lose', resulting in a fairly nonrigid looking result. For more rigidity, you can try bumping up the corrective impulse, but that can result in some unusual side effects in extreme cases. Direct position modification can work too, but then you import the problems associated with teleportation.

(The highest quality and greatest effort path would be to create a unidirectional constraint- similar to a regular contact, except only pushing back on one of the two involved entities. Can't really recommend this- it would get complicated.)
There's a final consideration which I don't know if this should go in a separate thread or if the consideration makes change some of the answers for some NPC types. CharacterCollider uses a Cylinder, but some NPC shapes should be something other than a Cylinder.
While using non-cylinder shapes can work (see the SphereCharacterController), upstepping/downstepping will not behave properly in general. You might be able to get away with using a rounded box or something similar to allow to climb over small obstacles, but otherwise, it's going to be tricky.
2-Some NPCs are dogs or people mounting a moving horse. I could approximate a dog with a cylinder because it's small, but the horse is unlikely to give good results.
That's a bit of a tough case. Horses in particular have a lot of unique properties which make them difficult to unify with a traditional character controller. They aren't approximately rotationally invariant, they have dramatically different stepping behavior, turning and strafing work differently, and so on. Realistically, if you wanted a high quality specialized result, it would require a custom implementation.

You might be able to just get away with ignoring those issues and using a regular character, though. For example, add a bit of AI that makes the horse less inclined to jam its face through walls, even if physics permits it.

Re: Need advice in several issues

Posted: Wed Jun 27, 2018 9:05 pm
by KakCAT
Hi Norbo, thanks a lot for your answers!

Unfortunately the horse can't be fixed with AI, as the main problem is the player controlled character walking around (and through) the horse.
But this gave me some ideas for NPCs 1&2

For type 1: There's no need to not be able to push the player: As soon as the player is detected, just stop moving. As player can now always be pushed I suppose I can bring it back to the standard character controller.

So now Type 2 NPC being non-movable may be given a big mass compared to the played and that would make him very hard to be moved, and very minimal movement correction in AI would do the rest.


However the horse and the square-shaped characters have made me think that a Character Controller for the NPCs may not be the best solution.
I should probably use plain entities instead of char controllers and try to move them. My problem is that I'm very afraid of using forces and impulses because it's often recipe for chaos when you don't know what you're doing :)

Q: Is modifying the entity's Velocity (Linear and Angular) an acceptable practice? (I'm aware that modifying position or other kinds of teletransportation are not recommended)
If not, what's the recommended way to keep a character at approx. constant speed?

(The upstepping should't be a problem because I plan to replace all steps with ramps, as I didn't like the step jump the characters do anyways)

Q:Is using LocalInertiaTensorInverse = new Matrix (0,0,0 0,1,0, 0,0,0) the correct way to lock all rotations for an object except for axis Y? (I will need that for elongated characters)


Thanks again!

Re: Need advice in several issues

Posted: Wed Jun 27, 2018 10:11 pm
by Norbo
Q: Is modifying the entity's Velocity (Linear and Angular) an acceptable practice? (I'm aware that modifying position or other kinds of teletransportation are not recommended)
If not, what's the recommended way to keep a character at approx. constant speed?
Directly controlling velocity can work. It's equivalent to applying an impulse, and can sometimes be simpler to think about.

The main problem with applying impulses or controlling the velocity is that it is a discrete operation that takes place outside of the solver. You can think of it like poking the entity 60 times per second. It is *almost* continuous, but not quite. It won't produce the same result as the same behavior implemented as a constraint, like the character controller's HorizontalMotionConstraint. This becomes most apparent during 'difficult' circumstances with lots of competing influences.

I don't want to make it sound worse than it is, though- you can definitely make a game that relies solely on velocity or impulses rather than constraints, you just have to be aware of the corner cases where it won't work quite as well.

A secondary issue with velocity control is that simply setting velocity to, say, (1,0,0) to make the character move along X will also remove any falling velocity. To avoid that kind of issue, you have to be careful about what degrees of freedom you're modifying.

(A side note for v2 alpha: at the moment, position integration actually occurs at the beginning of the frame instead of the end. This has some beneficial effects, but it means that velocity control outside of the simulation update will directly influence position without giving the solver a chance to correct it. Velocity/force based control can still work in such a scheme, but it would be best to do the work in a callback triggered after position integration. I might end up reverting this to the v1 position-integration-at-the-end if it ends up being too unwieldy.)
Q:Is using LocalInertiaTensorInverse = new Matrix (0,0,0 0,1,0, 0,0,0) the correct way to lock all rotations for an object except for axis Y? (I will need that for elongated characters)
Yup. The alternative would be a constraint, but a constraint will be softer and more expensive. Inertia tensor modifications are essentially free and will never be violated.