How to make a 3D RTS in Godot 3.1 part 2 - Unit Selection and Teams

Поделиться
HTML-код
  • Опубликовано: 21 окт 2024

Комментарии • 34

  • @lethn2929
    @lethn2929 Год назад +7

    Okay, since this seems to be one of the only comprehensive tutorials on the internet about RTS selection and it is sadly very out of date, like some of you guys I suspect, I came across this tutorial and couldn't get anywhere with it so I ended up working on the code to update it get it running for Godot 4. This is 100% confirmed working and I also threw in some deselect for you because honestly there is not enough documentation out there in general for selection boxes beyond 2D. You still need to setup groups and so on but this should all work.
    extends Node3D
    @onready var camera = $PlayerCamera
    @onready var selectionBox2D = $PlayerCamera/SelectionBox2D
    var startSelectionPosition = Vector2()
    var mouseClickCollider3DResult
    var raycastMouseClick3DResult
    var mousePosition
    var selection = []
    var newSelection = []
    var focusFireTargetCollider
    var sideBarMouseEntered = false
    @onready var mouseRaycastGroup = get_tree().get_nodes_in_group("MouseRaycast")
    @onready var mouseRaycast = mouseRaycastGroup[0]
    func _physics_process(delta):
    mousePosition = get_viewport().get_mouse_position()


    if Input.is_action_just_pressed("LeftClick"):
    selectionBox2D.startSelectionPosition = mousePosition
    startSelectionPosition = mousePosition

    for selected in selection:
    selected.DisableSelectionRing()

    if Input.is_action_pressed("LeftClick"):
    selectionBox2D.mousePosition = mousePosition
    selectionBox2D.isVisible = true
    else:
    selectionBox2D.isVisible = false
    if Input.is_action_just_released("LeftClick"):
    SelectUnits()

    if Input.is_action_just_pressed("Rightclick") && selection.size() != 0:
    for selected in selection:
    if selected.SR.visible == false:
    return
    else:
    RaycastMouseClick()
    selected.beanSoldier.speed = 600
    selected.beanSoldier.beanNA.set_target_position(raycastMouseClick3DResult)
    selected.beanSoldier.hasStopped = false
    selected.beanSoldier.combatRange.combatTimer.stop()
    selected.beanSoldier.combatRange.hasCombatTimerStarted = false

    RaycastFromMouse()
    focusFireTargetCollider = mouseClickCollider3DResult
    if focusFireTargetCollider.is_in_group("Enemy"):
    selected.beanSoldier.combatRange.focusFireTarget = mouseClickCollider3DResult
    selected.beanSoldier.beanNA.set_target_position(focusFireTargetCollider.global_transform.origin)
    print(selected.beanSoldier.combatRange.focusFireTarget.name)
    else:
    selected.beanSoldier.combatRange.focusFireTarget = null
    func SelectUnits():
    newSelection = []
    if mousePosition.distance_to(startSelectionPosition) < 16:
    var u = GetUnitUnderMouse()
    if u != null:
    newSelection.append(u)
    else:
    newSelection = GetUnitsInBox(startSelectionPosition, mousePosition)
    if newSelection.size() != 0:
    for selected in newSelection:
    selected.EnableSelectionRing()
    selection = newSelection


    func GetUnitUnderMouse():
    var result = mouseClickCollider3DResult
    if result != null && result.is_in_group("Selectable"):
    return result.collider
    func GetUnitsInBox(topLeft, bottomRight):
    if topLeft.x > bottomRight.x:
    var temp = topLeft.x
    topLeft.x = bottomRight.x
    bottomRight.x = temp
    if topLeft.y > bottomRight.y:
    var temp = topLeft.y
    topLeft.y = bottomRight.y
    bottomRight.y = temp
    var box = Rect2(topLeft, bottomRight - topLeft)
    selection = []
    for selected in get_tree().get_nodes_in_group("Selectable"):
    if box.has_point(camera.unproject_position(selected.global_transform.origin)):
    selection.append(selected)
    return selection
    func RaycastMouseClick():
    var spaceState = get_world_3d().direct_space_state
    var raycastOrigin = camera.project_ray_origin(mousePosition)
    var raycastTarget = raycastOrigin + camera.project_ray_normal(mousePosition) * 5000
    var physicsRaycastQuery = PhysicsRayQueryParameters3D.create(raycastOrigin, raycastTarget)
    var raycastResult = spaceState.intersect_ray(physicsRaycastQuery)

    if raycastResult.is_empty():
    return
    else:
    raycastMouseClick3DResult = raycastResult["position"]

    func RaycastFromMouse():
    var spaceState = get_world_3d().direct_space_state
    var raycastOrigin = camera.project_ray_origin(mousePosition)
    var raycastTarget = raycastOrigin + camera.project_ray_normal(mousePosition) * 5000
    var physicsRaycastQuery = PhysicsRayQueryParameters3D.create(raycastOrigin, raycastTarget)
    var raycastResult = spaceState.intersect_ray(physicsRaycastQuery)

    if raycastResult.is_empty():
    return
    else:
    mouseClickCollider3DResult = raycastResult["collider"]

    func RaycastNodePosition():
    var spaceState = get_world_3d().direct_space_state
    var mousePosition = get_viewport().get_mouse_position()
    var raycastOrigin = camera.project_ray_origin(mousePosition)
    var raycastTarget = raycastOrigin + camera.project_ray_normal(mousePosition) * 5000
    mouseRaycast.target_position = Vector3(raycastTarget)
    func _on_side_bar_control_mouse_entered():
    sideBarMouseEntered = true
    func _on_side_bar_control_mouse_exited():
    sideBarMouseEntered = false

  • @MrPhilosomanic
    @MrPhilosomanic 2 года назад +3

    Holy crap THANK YOU. I've spent so much time trying to figure out janky ways to do this, but I had no clue that unprojecting a 3d position into a 2d position on the screen was even possible. This is a 10/10 tutorial - very easy to understand and straight to the point.

  • @Crisisdarkness
    @Crisisdarkness 5 лет назад +9

    Wow this is great, with you there is so much to learn, being honest with you, I have many videos pending on your channel, but I'm happy to see so much interesting content. Thanks for continuing to advance in this genre, you are doing amazing things

  • @thedevilhimself1728
    @thedevilhimself1728 4 года назад +33

    Wish you continued this series :[

    • @nopens
      @nopens 3 года назад

      Yeah, even though it server a great example off rts basics, mainly camera and peojecting 2d mouse coordinates onto 3d world, there's so much more to cover. Minimap for example.

  • @lukevost
    @lukevost 5 лет назад +17

    Thanks! Hope you will continue this series! =)

  • @lethn2929
    @lethn2929 Год назад +5

    And then also here's the 2D Selection Box for you because a bit of the code has changed for that in Godot 4 too, well one function really but it's barely mentioned in documentation.
    extends Control
    var isVisible = false
    var mousePosition = Vector2()
    var startSelectionPosition = Vector2()
    var selectionBoxColor = Color(0, 1, 0)
    var selectionBoxLineWidth = 1
    func _draw():
    if isVisible and startSelectionPosition != mousePosition:
    draw_line(startSelectionPosition, Vector2(mousePosition.x, startSelectionPosition.y,), selectionBoxColor, selectionBoxLineWidth)
    draw_line(startSelectionPosition, Vector2(startSelectionPosition.x, mousePosition.y), selectionBoxColor, selectionBoxLineWidth)
    draw_line(mousePosition, Vector2(mousePosition.x, startSelectionPosition.y), selectionBoxColor, selectionBoxLineWidth)
    draw_line(mousePosition, Vector2(startSelectionPosition.x, mousePosition.y), selectionBoxColor, selectionBoxLineWidth)

    func _process(_delta):
    queue_redraw()

  • @industrialdonut7681
    @industrialdonut7681 4 года назад

    This is pretty clean, literally easier to follow than some other tutorials despite the pacing being fast and the end result not insignificant by any means

  • @XerotoLabs
    @XerotoLabs 5 лет назад

    Great Tut man . it answered a hand full of things I was wondering if Godot could do. I'll have to figure out flocking, avoidance, and steering as I will try to apply this to ships.
    a very clear example, nice and easy to follow along.

  • @volodymyrsaruta4385
    @volodymyrsaruta4385 5 лет назад +4

    Thanks for video! :) Would be great to fix the issue when they fight for the spot (bump in to each other), which you mentioned in previous video!

  • @soundsbeard
    @soundsbeard 5 лет назад

    this is so cool, I love it! keep it up man!

  • @fredericklebeault3467
    @fredericklebeault3467 5 лет назад +4

    Hey Miziziziz
    How would you do to make your units look at the direction they are moving?

    • @adammikulis6211
      @adammikulis6211 4 года назад +1

      I found that this method only makes them look at the target position initially but not always a full rotation. This worked for me in the func move_to(target_pos) in the unit script:
      look_at(target_pos, Vector3(0,1,0)). If your unit is looking the opposite way just make it -target_pos. Thanks for pointing me in the right direction!

  • @aztecasensei6124
    @aztecasensei6124 5 лет назад +4

    pure genius!

  • @aloufin
    @aloufin 4 года назад +3

    my selection rings kinda get clipped by the floor.... does this have to do with the 'agent height' in the nav mesh settings?
    Edit: The fix was to move higher all child nodes of Unit's kinematicBody root

    • @lethn2929
      @lethn2929 Год назад

      As of Godot 4 you now have 3D decals which mean you can project selection rings onto the ground without any code.

  • @gingerageousgames613
    @gingerageousgames613 5 лет назад

    Amazing video. Great content. Clear and concise.

  • @boboop94
    @boboop94 4 года назад +1

    Hope the part 3 will come someday :3

    • @favkisnexerade
      @favkisnexerade 3 года назад

      Part 3 probably contains dynamic obstacles and thats where you drop godot and go to unity

  • @F1ory
    @F1ory 2 года назад

    Thanks, Hello from Kazakstan

  • @nicknick1807
    @nicknick1807 4 года назад

    Please, continue tutor, it helps me more then school(

  • @MarkIsAsleep
    @MarkIsAsleep 3 года назад +1

    Why are they not looking towards direction

  • @ahmadtakhimi6839
    @ahmadtakhimi6839 5 лет назад +1

    Can you please add avoidance and steering behavior tutorial next ? Thanks

  • @juhamukari9285
    @juhamukari9285 3 года назад

    hmm.. is there full rts game develop tutorial with godot? this was very interesting.
    Good tutorials.

  • @hoohohohter
    @hoohohohter 3 года назад +1

    Why is my selecrion box not visible?

  • @juhamukari9285
    @juhamukari9285 3 года назад

    Is there coming part 3? :)

  • @favkisnexerade
    @favkisnexerade 3 года назад

    Thats where 3d rts game ends for everyone I guess cause navigation in godot is awful and the only existing addon for dynamic navmesh changing is broken

  • @cassangel7561
    @cassangel7561 5 месяцев назад

    very good

  • @laud4064
    @laud4064 5 лет назад

    Hey there Miz, I have a request.
    I would like to learn how to make a shitty generic 3d horror game using Godot. My math is trash, and I still can't make a simple game in Godot because I can't wrap my mind around the nodes blah blah system. Prior to this, I could make shitty 2d games in Game Maker without much trouble.
    Can you give me some advice? Maybe give me some things to work on?
    Thanks.

    • @Miziziziz
      @Miziziziz  5 лет назад +4

      You could start with the 3d platformer tutorial I have and just move the camera in close to make it first person. Then I guess just check out unity tutorials on making horror games for ideas. Mechanically horror games are pretty simple, it's mostly about making atmosphere

  • @alfredkoehne6429
    @alfredkoehne6429 3 года назад

    3rd part please!

  • @chwdpjd100
    @chwdpjd100 2 года назад +3

    sus

  • @cientificopsi2361
    @cientificopsi2361 3 года назад

    can you do same in c#?

    • @anixias
      @anixias 3 года назад

      I did it in C# if you want the code.