feat: player controls commenting pass
This commit is contained in:
parent
99b844cc76
commit
4f564a4f4c
|
@ -23,8 +23,12 @@ void PlayerCharacter::_process(double delta_time) { GDGAMEONLY();
|
|||
}
|
||||
|
||||
void PlayerCharacter::_physics_process(double delta_time) { GDGAMEONLY();
|
||||
// accelerate towards velocity target
|
||||
Vector3 const new_velocity = this->get_velocity().move_toward(this->velocity_target, delta_time * PlayerCharacter::ACCELERATION);
|
||||
this->set_velocity(new_velocity);
|
||||
// only apply velocity if not grounded
|
||||
Vector3 const gravity{this->is_on_floor() ? Vector3() : Vector3{0.f, this->get_velocity().y - 9.8f, 0.f}};
|
||||
this->set_velocity(new_velocity + gravity);
|
||||
// update position
|
||||
this->move_and_slide();
|
||||
}
|
||||
|
||||
|
@ -33,9 +37,12 @@ void PlayerCharacter::move(Vector3 world_vector) {
|
|||
}
|
||||
|
||||
void PlayerCharacter::aim(Vector3 at) {
|
||||
// calculate the forward vector by normalized difference between this node and the target
|
||||
Vector3 const position{this->get_global_position()};
|
||||
Vector3 const forward{(Vector3{at.x, 0.f, at.z} - Vector3{position.x, 0.f, position.z}).normalized()};
|
||||
// we always want up to be the global unit up
|
||||
Vector3 const up{0.f, 1.f, 0.f};
|
||||
// left is the cross product of the two
|
||||
this->target_rotation = Basis{up.cross(forward), up, forward};
|
||||
}
|
||||
|
||||
|
@ -65,14 +72,20 @@ void PlayerCharacter::process_ai(double delta_time) {
|
|||
}
|
||||
|
||||
void PlayerCharacter::process_rotation(double delta_time) {
|
||||
// copy the current transform and basis matrix
|
||||
Transform3D trans{this->get_global_transform()};
|
||||
Basis basis = trans.get_basis();
|
||||
// construct the current rotation ..
|
||||
Quaternion const current_quaternion = basis.get_rotation_quaternion();
|
||||
// .. and the target rotation from their respective bases
|
||||
Quaternion const target_quaternion = this->target_rotation.get_rotation_quaternion();
|
||||
// calculate the angle that still needs to be traveled
|
||||
float const angle = current_quaternion.angle_to(target_quaternion);
|
||||
basis.set_quaternion(angle >= delta_time * PlayerCharacter::ROTATION_SPEED
|
||||
? current_quaternion.slerp(target_quaternion, delta_time * (this->rotation_speed_curve->sample(angle) * PlayerCharacter::ROTATION_SPEED) / angle)
|
||||
: target_quaternion);
|
||||
// calculate the angle amount that can be moved this frame
|
||||
float const angle_step{float(this->rotation_speed_curve->sample(angle) * PlayerCharacter::ROTATION_SPEED * delta_time)};
|
||||
// update this object's global transform with the new rotation
|
||||
basis.set_quaternion(angle < angle_step ? target_quaternion // to avoid overshooting, check if the max step is smaller than the angle distance
|
||||
: current_quaternion.slerp(target_quaternion, angle_step / angle)); // convert the angle step to a lerp t value between current and target rotations
|
||||
trans.set_basis(basis);
|
||||
this->set_global_transform(trans);
|
||||
}
|
||||
|
|
|
@ -31,20 +31,27 @@ void TunnelsPlayer::_exit_tree() { GDGAMEONLY();
|
|||
}
|
||||
|
||||
void TunnelsPlayer::_process(double delta_time) { GDGAMEONLY();
|
||||
this->process_mouse_location(delta_time);
|
||||
this->process_mouse_location(delta_time); // get the current screen location of the cursor
|
||||
// convert screen location to world location on the same y plane as the player character
|
||||
Vector3 const mouse_world_location = this->get_mouse_world_position(Vector3{0.f, 1.f, 0.f}, this->character->get_global_position().y + 1.f);
|
||||
// move the reticle
|
||||
this->reticle->set_global_position(mouse_world_location);
|
||||
// rotate the camera
|
||||
this->process_camera_rotation(delta_time);
|
||||
switch(this->state) {
|
||||
default:
|
||||
case State::ManualControl:
|
||||
// send the current wasd input to the character
|
||||
this->character->move(this->get_world_move_input().normalized());
|
||||
// send the current world cursor position the character
|
||||
this->character->aim(mouse_world_location);
|
||||
// move the camera along with the character
|
||||
this->set_global_position(this->character->get_global_position());
|
||||
break;
|
||||
case State::Tactics:
|
||||
break;
|
||||
case State::Overview:
|
||||
// move camera along with the input
|
||||
this->set_global_position(this->get_global_position() + this->get_world_move_input().normalized());
|
||||
break;
|
||||
}
|
||||
|
@ -53,15 +60,20 @@ void TunnelsPlayer::_process(double delta_time) { GDGAMEONLY();
|
|||
void TunnelsPlayer::process_mouse_location(double delta_time) {
|
||||
Viewport *view = this->get_viewport();
|
||||
Vector2 const pixel_location = view->get_mouse_position();
|
||||
// convert cursor's global pixel position to normalized screen coordinates
|
||||
this->mouse_location = pixel_location / view->get_visible_rect().get_size();
|
||||
// get the direction the mouse is pointing in the world
|
||||
this->mouse_world_ray_normal = this->camera->project_ray_normal(pixel_location);
|
||||
}
|
||||
|
||||
void TunnelsPlayer::process_camera_rotation(double delta_time) {
|
||||
Vector3 rotation = this->get_global_rotation();
|
||||
float const y_multiplier = std::max(0.1f, this->mouse_location.y);
|
||||
float const y_multiplier = std::max(0.4f, this->mouse_location.y); // the influence of the mouse's y position on the rotation speed
|
||||
// rotate the camera when the mouse is close to the edge of the screen
|
||||
if(this->mouse_location.x < TunnelsPlayer::ROTATION_MARGIN) {
|
||||
// normalized measurement of how far into the rotation margin the mouse is
|
||||
float const normalized{1.f - (this->mouse_location.x / TunnelsPlayer::ROTATION_MARGIN)};
|
||||
// rotate based on delta time and use a curve to make the rotation zone feel more natural
|
||||
rotation.y += delta_time * TunnelsPlayer::ROTATION_SPEED * camera_rotation_ramp->sample(normalized) * y_multiplier;
|
||||
}
|
||||
if(this->mouse_location.x > 1.f - TunnelsPlayer::ROTATION_MARGIN) {
|
||||
|
@ -74,6 +86,7 @@ void TunnelsPlayer::process_camera_rotation(double delta_time) {
|
|||
rotation.y -= 6.283185;
|
||||
while(rotation.y < 0.f)
|
||||
rotation.y += 6.283185;
|
||||
// apply new rotation
|
||||
this->set_global_rotation(rotation);
|
||||
}
|
||||
|
||||
|
@ -101,11 +114,11 @@ void TunnelsPlayer::initialize_character() {
|
|||
return;
|
||||
if(player_scene->get_state()->get_node_type(0) != StringName("PlayerCharacter"))
|
||||
return;
|
||||
// instantiate and store as player character
|
||||
// instantiate and store the player character
|
||||
this->character = Object::cast_to<PlayerCharacter>(player_scene->instantiate());
|
||||
this->get_parent()->add_child(this->character);
|
||||
this->character->set_global_transform(this->get_global_transform());
|
||||
// toggle manual mode, meaning the character's navigation agent is disabled and direct input to move(..) is used instead
|
||||
// disable navmesh navigation and start using player input
|
||||
this->character->set_manual_mode(true);
|
||||
}
|
||||
|
||||
|
@ -124,9 +137,12 @@ Vector3 TunnelsPlayer::get_world_move_input() const {
|
|||
}
|
||||
|
||||
Vector3 TunnelsPlayer::get_mouse_world_position(Vector3 axis, float depth) const {
|
||||
// cache camera location
|
||||
Vector3 const cam_origin = this->camera->get_global_position();
|
||||
// get the ray and origin depths along the axis
|
||||
float const cam_depth = axis.dot(cam_origin);
|
||||
float const ray_step = axis.dot(this->mouse_world_ray_normal);
|
||||
// calculate the number of "steps" the ray needs to take to get the target depth from the origin along the axis
|
||||
float const distance = depth - cam_depth;
|
||||
float const steps = distance / ray_step;
|
||||
return cam_origin + this->mouse_world_ray_normal * steps;
|
||||
|
|
Loading…
Reference in a new issue