Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New physics based first/third person 3d and platformer like modular navigation + input axis and others #533

Open
wants to merge 384 commits into
base: master
Choose a base branch
from

Conversation

and3md
Copy link
Contributor

@and3md and3md commented Sep 19, 2023

Because our current navigation system is quite difficult to modify. We were looking for a way to add navigation that would be, on the one hand, quick to add and, on the other hand, easy to modify. This can be achieved in two ways:

  • add a simple behavior that contains the most basic functions (e.g. limited to moving and jumping) and let game programmer add/modify anything other he needs - this gives full control but also need a lot of work
  • create a system that can be expanded using smaller modules - in this case we have main behavior and a lot smaller that does only one thing like head bobbing, flying support, crouch support and game programmer add these modules to player transform and can implement his own modules when he need something that works different

This PR adds two such possibilities. In all cases we assume that player transform has rigid body and collider.

In the case of the first approach, I implemented two behaviors TSimplestFpsPlayerMovement and TSimpleFpsPlayerMovementWithRotation intended only for FPS games.

TSimplestFpsPlayerMovement

This is the simplest one it assumes that rigid body has blocked rotations and movement direction is determined by the camera direction.

It has few properties:

Property Description
JumpSpeed jump speed (Single value)
HorizontalSpeed speed of movement in X,Z axes (Single value)
ForwardInputAxis the new input axis for forward/backward direction
SidewayInputAxis the new input axis for left/right direction
InputJump input (key) for jump

In this case Player (TCastleTransform) should have camera as his child:

obraz

For camera rotations we use TRotateCamera behavior .

TSimplestFpsPlayerMovement will only work well in the simplest of situations when we do not care about (invisible in FPS game) player rotation. And as I wrote it has only base functions (move and jump) and it is intended to be copied and modified by the game developer.

TSimpleFpsPlayerMovementWithRotation

This behavior is similar to TSimplestFpsPlayerMovement but horizontal rotation (x axis) is made by rotating rigid body (using new TRotateRigidBody behavior.

The properties are the same like in TSimplestFpsPlayerMovement:

Property Description
JumpSpeed jump speed (Single value)
HorizontalSpeed speed of movement in X,Z axes (Single value)
ForwardInputAxis the new input axis for forward/backward direction
SidewayInputAxis the new input axis for left/right direction
InputJump input (key) for jump

In this case Player (TCastleTransform) should have camera as his child and be configured like that:

obraz

The only difference is using TRotateRigidBody for horizontal rotation (y axis) and now in TRotateCamera we rotate camera only vertical (x axis).

But this behavior is also only a start point for game developer that wants do anything in his own way. But what if we don't want implement everything by ourself but still want modify it? We should use TModularMovement

TModularMovement

TModularMovement is navigation system that can be used for all types of games like FPS, TPP and also 2D games.
For most usecases, it is enough to use the modules that we have prepared, and if something is missing or should work differently, game programmer can create another module or modify the existing one.

How does it work?

At first we add TModularMovement and then other modules depending on your needs e.g.

For 2D platformer like game we add TPlatformer2DWalkSupport - that covers jumping, moving left and right out of the box. When we want add double jump we just add TDoubleJumpSupport. All modules have also Exists property so when we want add double jump when player achieve something we simply set exists to false in editor and set to true in right moment.

Similarly for an FPS game we will add TWalk3DSupport for player moving if we want head bobbing simply add THeadBobbing for crouch TFpsCrouch et cetera.

How it works underneath?

TModularMovement has only three functions:

  • gets input
  • checks player is on ground
  • search all modules and run them in update.

All modules inherit from TAbstractMovementModule and implements/overides UpdateMovement() function.

Properties

Property Description
ForwardInputAxis the new input axis for forward/backward direction
SidewayInputAxis the new input axis for left/right direction
InputJump input (key) for jump
GroundPhysicsLayers physics layers used for ground checking

Configuration

This all may seem complicated it is really easy and a lot of things can be achieved without coding any single line of code.

FPS game

obraz

See castle-engine/examples/physics/physics_3d_shooter example.

TPP game:

Here we also use TFollowingTargetForCamera behavior in camera that supports following an object by 3d camera without writing any line of code.

obraz

See castle-engine/examples/physics/physics_3d_third_person example.

Platformer game

obraz

See examples/physics/physics_2d_movement

All modules list

Module Description
TAnimationTrigger Basic animation trigger for TPP game
TFpsCrouch Crouch support
TFly3DSupport Fly support for 3d games
TWalk3DSupport Walk for 3d games
THeadBobbing Head bobbing for FPS games
TStairsSupportByColliderCapsuleRadius Walking on staris support when collider friction > 0
TPlatformer2DWalkSupport 2D platformer walking support
TPlatformer2DInAirControl Ability to control player in air (2d games)
TDoubleJumpSupport Support for double jump (2d and 3d games)
TInAir3DControl In air control for 3D games

Other behaviors

Behaviors that can be usable in many use cases:

Behavior Description
TDirectRotateTransformByKeys Behavior for rotate object by keyboard (do not use with physics objects)
TFollowingTargetForCamera Behavior for Camera to follow Target (like in TPP games)
TRotateCamera Behavior for rotate camera
TRotateRigidBody Behavior for rotate rigid body by input axis

Input Axis

I implemented simple Input Axis that observes some keys/mouse and returns a value. More info in docs. How to use check other behaviors. (this PR description is getting to long)

Simple way to use mouse look

There are tow new functions in TCastleContainer: StartMouseLook() and StopMouseLook(); After StartMouseLook() Container starts update MouseLookLastDelta that can be used everywhere in your game. See TCastleInputAxis Value function and castle-engine/examples/physics/physics_3d_shooter main unit for example

Simple way to use mouse drag

There are tow new functions in TCastleContainer: StartMouseDrag() and StopMouseDrag(); After StartMouseLook() Container starts update MouseDragDelta that can be used everywhere in your game. See TCastleInputAxis.Value() function and castle-engine/examples/physics/physics_3d_shooter man unit for example

Simple way to use mouse wheel everywhere

There is LastUpdateMouseWheelDirection in TCastleContainer that contains mose wheel direction change from latest frame

Cached Collider and RigidBody in TCastleTransform

Now you don't need call FindBehavior every frame just get it by using cached pointers from TCastleTransform.

Some screenshots

Platformer game without writing any code:

obraz

TPP example:

obraz

FPS game:

obraz

More tips for TModularMovement

FPS - How To Use it:
- Player rigid body can rotate only in Y axis (horizontal), other axes
  should be blocked in rigid body
- Y is always up
- Friction in player collider should be 0 - with other friction values
  using stairs needs extra code like TStairsSupportByColliderCapsuleRadius,
  and can have other undesirable problems during contact, e.g. with walls
- Rotate player horizontal using angular velocity (do not change transform
  Rotation directly that leads to physics objects synchronization and
  can make your player can fall off the level - especially when it's done
  every frame) You can use TRotateRigidBody behavior for that purpose.
- Do not rotate player vertical - rotate camera. You can use TRotateCamera
  behavior for that.
- Do not change player translation every frame - use rigid body velocities/forces
- After adding TModularMovement add some movement modules e.g. TWalk3DSupport
- Do not afraid to change/add your own movement modules - this class is
  designed for that :)
- Camera should be rotated by pi in y axis for FPS movement
- See /examples/physics/physics_3d_shooter
- For mouse look use Container.StartMouseLook(Viewport); and Container.StopMouseLook;

TPP - How To Use:
- Player rigid body can rotate only in Y axis (horizontal), other axes
  should be blocked in rigid body
- Y is always up
- Friction in player collider should be 0 - with other friction values
  using stairs needs extra code like TStairsSupportByColliderCapsuleRadius,
  and can have other undesirable problems during contact, e.g. with walls
- Rotate player horizontal using angular velocity (do not change transform
  Rotation directly that leads to physics objects synchronization and
  can make your player can fall off the level - especially when it's done
  every frame) You can use TRotateRigidBody behavior for that purpose.
- For cammera following you can use TFollowingTargetForCamera behavior (add it
  to your camera )
- After adding TModularMovement add some movement modules e.g. TWalk3DSupport
- Do not afraid to change/add your own movement modules - this class is
  designed for that :)
- For mouse look use Container.StartMouseLook(Viewport); and Container.StopMouseLook;
- See /examples/physics/physics_3d_third_person

2D Platformer Game - How To Use:
- Player rigid body rotation should be blocked in all directions
- Player translation in Z axis should be blocked
- GravityStrength should be about 1200 (9.81 is good for 3D games)
- After adding TModularMovement add some movement modules e.g. TPlatformer2DWalkSupport
- Do not afraid to change/add your own movement modules - this class is
  designed for that :)
- See /examples/physics/physics_2d_movement

and3md added 30 commits May 29, 2023 13:18
… ShouldDoDefaultMovement(). Change fly/walk in game code.
…layer's collider has friction player can't rotate.
…to fix all errors and make it much easier to use physics ray/sphere cast.
… ground using the new TCastleCollider.Middle().

Also removed Michalis TODO - will never be done in that class we work on new navigation system.
@michaliskambi
Copy link
Member

Poor GitHub will explode from our big pull requests :)

Thank you!

To everyone who reads this -- this a big, big new feature (actually a combination of a few things) that Andrzej has been working on for a while, and we've talked about a lot of details of this together. It's a set of behaviors that allow to easily set up a working navigation (for a wide range of games, as you can see in the description above -- 1st person 3D, 3rd person 3D, 2D like platformer...). It also adds TCastleAxis, a great new approach to monitor inputs in CGE. See the description above for details.

If anyone wants to test it at this point -- go ahead. You can get from GitHub the branch https://github.com/castle-engine/castle-engine/tree/physics_third_person_navigation , and compile the CGE using https://castle-engine.io/compiling_from_source.php . Feedback is most appreciated.

@and3md
Copy link
Contributor Author

and3md commented Sep 20, 2023

I forgot to add info about changes in our physics. Kraft has been updated and I also fixed one rare crash (BeRo1985/kraft#33).

Our rigid body support now sphere casting (TCastleRigidBody.PhysicsSphereCast()) so we do not need to cast many rays to check some things like in current master.

Physics ray cast itself has also new parameter CollisionLayers so you can choose on which layers ray cast can hit. Sphere cast also has this parameter.

In colliders there is new function that return scaled bounding box of collider (ScaledLocalBoundingBox()). Because relying on the bounding box of the TCastleScene with running animation can cause glitches in various situations. Especially when casting rays and check some distances.

michaliskambi added a commit that referenced this pull request Mar 15, 2024
Also adds CollisionLayers to PhysicsRayCast, following code from #533 too.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants