Soulslike 3D Controller and Camera in Godot 4 | Part I

Поділитися
Вставка
  • Опубліковано 21 вер 2024

КОМЕНТАРІ • 17

  • @nonamenoah7407
    @nonamenoah7407 4 місяці тому +1

    This tutorial is well paced, explains a lot of the decisions, shows the math, but doesn't show too much as to make less experienced devs just copy paste the chunks into their own game, and instead makes you think about how you would implement this system within your already existing features. Truly a great tutorial, thank you for this.

    • @PointDown
      @PointDown  4 місяці тому +2

      Holy shit, someone watched it after a month :D. Improving production by small steps is starting to bear fruits I suppose. Yep, I'm trying to make architecture talks the core theme of the channel, even if it'll potentially loose me some views, at least, the Godoverse will become a bit better place. Glad you enjoyed and thank you for your support, it means a lot for me).

  • @IkeyIlex
    @IkeyIlex Місяць тому

    I'm definitely gonna use this guide, this kind of thing would make my game feel so much better!

  • @ink_nightjar
    @ink_nightjar 5 місяців тому +1

    legend starts here, mark my words!

  • @RyuNoAniki
    @RyuNoAniki Місяць тому

    when calculating the camera rotation/offset (8:18) I keep getting the error "The axis Vector3 (0, 0, 0) must be normalized."

    • @PointDown
      @PointDown  Місяць тому

      Vector (0,0,0) has no length and can't be used as an axis to drscribe rotation.

  • @Gambarus
    @Gambarus 4 місяці тому

    Привет. Спасибо за туториалы. Лайк, подписка и вот это вот все 👍
    Два вопроса:
    1. Можно ли пощупать исходники по камере? Без них как-то грустно.
    2. Ролики на русском не планируются?

    • @PointDown
      @PointDown  4 місяці тому

      1) Пока низя). Но у меня есть серия про контроллер на гитхабе, там буквально есть в конечном автомате персонажа состояния Run и Sprint. Меняешь их код на буквально скрины, и уже почти работает, осталось только саму камеру приделать, структура нод и буквально все, что нужно в видосе есть. Он специально так сделан, мооожет быть, выдам код, если прям миллиард вопросов будет и структурно в будущих сериях будет подходить.
      2) Не думаю, мб сабами запарюсь, если пойму, что выхлоп будет соотносим с затратами сил.

  • @zackarysemancik5491
    @zackarysemancik5491 3 місяці тому

    At 5:31, would you mind explaining how you get this orbiting value and orbiting curved?
    My understanding is that the orbiting value is simply a component of the input vector, but I'm not sure how you got the curved value.
    Looking at the diagram, how do you make sure the orbiting value isn't larger than the radius of the large circle below? If it is, would you be able to come up with the orbiting curved value?
    Thanks :D

    • @PointDown
      @PointDown  3 місяці тому

      5:52 is an explanation for orbiting vector. Base orbiting component is an input component. Orbiting curved then is strictly defined. And why is orbiting is lower then the circle - is "an implementation sense" detail. Orbiting component is the orbiting velocity of the character *per frame*. This is about 0.05 meters for a realistic running human speed, because a second has 60 phys-frames usually in 2024. And the camera arm length is just the camera arm length of several meters. Surely, the geometry problem solution will break on hight speeds, but you need to have 400+ km/h for it to start, and if that's the case I doubt you need a soulslike camera. The diagram has these proportions just for illustration purposes.

  • @rj_enoz
    @rj_enoz 2 місяці тому

    I am a begginer. 😅 Currently following the tutorial at 6:47.
    What is input internal?
    I wrote it and it could not find "input internal" in the current scope.

    • @PointDown
      @PointDown  2 місяці тому +1

      Ah, nevermind the name, it's just an input package. A data structure that holds my two imput vectors and some other things. I use a similar approach and talk about it more in the controller series. And a name InputInternal is for the fact that the project on screen is also a multiplayer, so I have InputInternal for local inputs transfering and InputSynchronized for sending to the server side. I will be remastering this something something Autumn, right now, it's a project with no source attached. Consider this just a number of geometry problems solved and don't copy code from screenshot line by line.

    • @rj_enoz
      @rj_enoz 2 місяці тому

      @@PointDown sorry for disturbing u again,
      currently, i not sure why but my visual(node that i turn into mesh ) is rotating toward the character.
      whileas I am unable to move the character.
      extends CharacterBody3D
      const RUN_SPEED := 10
      @export var visuals: Node3D # Reference to the Visual node
      @onready var local_camera: SoulsCamera = $LocalCamera # LocalCamera is a child of the CharacterBody3D
      @onready var player: CharacterBody3D = $"."
      @onready var movement_velocity = Vector3.ZERO
      class InputInternal:
      var direction : Vector2
      var target : Vector3
      func _init(direction : Vector2 = Vector2(), target : Vector3 = Vector3()):
      self.direction = direction
      self.target = target
      func get_forward() -> float:
      return direction.y
      func get_orbiting() -> float:
      return direction.x # Placeholder logic, adjust based on your specific orbit control
      func _ready():
      if not visuals:
      print("Visual node not found! Check the path to the visual node.")
      if not local_camera:
      print("LocalCamera node not found! Check the path to the LocalCamera node.")
      func _process(_delta):
      var input_internal = InputInternal.new()
      var move_right = Input.get_action_strength("Move_Right")
      var move_left = Input.get_action_strength("Move_Left")
      var move_back = Input.get_action_strength("Move_Back")
      var move_forward = Input.get_action_strength("Move_Forward")

      input_internal.direction = Vector2(
      move_right - move_left,
      move_back - move_forward
      )
      input_internal.target = global_position # Target is the position of the CharacterBody3D itself
      print("InputInternal direction: ", input_internal.direction)
      # Update character movement based on input and player state
      update(input_internal, self)
      func update(input_internal : InputInternal, player : CharacterBody3D):
      player.movement_velocity = velocity_by_input(input_internal, player)
      player.visuals.look_at(player.global_position - player.movement_velocity)
      player.move_and_slide()
      func velocity_by_input(input_internal : InputInternal, player : CharacterBody3D) -> Vector3:
      var from_center_speed : float = input_internal.get_forward()
      var orbit_speed : float = input_internal.get_orbiting()
      #print("From Center Speed: ", from_center_speed)
      #print("Orbit Speed: ", orbit_speed)
      if player.local_camera.is_target_locked:
      from_center_speed *= 1
      orbit_speed *= 1
      #print("Target Locked: Adjusted From Center Speed and Orbit Speed")
      if from_center_speed != 0:
      var grounded_target = input_internal.target
      grounded_target.y = 0
      movement_velocity -= player.global_position.direction_to(grounded_target) * from_center_speed * RUN_SPEED
      movement_velocity.y = 0
      print("Calculated Movement Velocity (From Center): ", movement_velocity)

      if orbit_speed != 0:
      var d: float = orbit_speed * RUN_SPEED / 60
      var grounded_target = input_internal.target
      grounded_target.y = 0
      var target_direction = grounded_target - player.global_position
      var distance_to_target = target_direction.length()
      var alpha = 2 * asin(d / (2 * distance_to_target))
      var d_vector = grounded_target - target_direction.rotated(Vector3.UP, alpha) - player.global_position
      movement_velocity += d_vector * 60
      print("Calculated Movement Velocity (Orbit): ", movement_velocity)



      movement_velocity = movement_velocity.limit_length(RUN_SPEED)
      return movement_velocity

    • @PointDown
      @PointDown  2 місяці тому +1

      @@rj_enoz Ooof, thats hard to do from a youtube comment. What I found is your target for some reason is your own character. That's incorrect, in unlocked mode, the target is gamera's position. Currently when you
      *var grounded_target = input_internal.target*
      grounded_target.y = 0
      movement_velocity -= *player.global_position.direction_to(grounded_target)* * from_center_speed * RUN_SPEED
      the resulting vector of direction is zero.
      Also for some reason, when "adjusting" to target locking, you multiplaying your values on 1 instead of -1.
      But that's just what I saw, I can't guarantee it will work if corrected, but at least you'll get a different bug, woo-hoo.)

    • @rj_enoz
      @rj_enoz 2 місяці тому

      @@PointDown Hey,
      Just wanted to let u know.
      That I have succeeded in fixing it.
      Thank you for replying to the comment.
      I was able to find that my input = was set to global_position instead of visual.global_position.
      Onto the next part of this tutorial (mouse movements)

  • @tumbochkalive9030
    @tumbochkalive9030 5 місяців тому

    Очень чётко слышно русский акцент

    • @PointDown
      @PointDown  5 місяців тому

      Можно пытаться маскировать это и пытаться в британское произношение из школы, а можно записаться в 7 раз быстрее). Мб если продолжу, со временем подвыправится.