Main Menu

RTS Movement Demo

Started by MudbuG, August 29, 2008, 02:14:33 PM

Previous topic - Next topic

MudbuG

I made this demo to test an idea I had about selecting and moving units around in an RTS game.  I couldn't find anything like this through searching the form, so I figured I would post it.


; PROJECT : RTSMovementDemo
; AUTHOR  : Damon Ellerbee
; CREATED : 8/29/2008
; EDITED  : 8/29/2008
; ---------------------------------------------------------------------

//I made this demo to test mouse control and primitiv RTS movement

Explicit

//=============================================================================
//
// Types
//
//=============================================================================

Type BoxInfo
  x1
  y1
  x2
  y2
EndType

Type WorldPos
  X As Float
  Y As Float
EndType

Type RTSUnit
  Selected
  Pos As WorldPos
  Destination As WorldPos
  Direction As Float
  Speed#
  Sprite
EndType

//=============================================================================
//
// Initialization
//
//=============================================================================

Constant purple = RGB(255, 0, 180)
Constant NormalColor = RGB(100, 100, 100)
Constant SelectedColor = RGB(100, 255, 100)

//Create friend images for sprites
Global FriendImg = NewImage(11, 11)
Global FriendSelectedImg = NewImage(11, 11)
CircleC 5, 5, 6, 1, RGB(80, 80, 80): GetImage FriendImg, 0, 0, 11, 11
CircleC 5, 5, 6, 1, RGB(80, 255, 80): GetImage FriendSelectedImg, 0, 0, 11, 11

//Make some friends (actors that belong to the player)
Dim Friend As RTSUnit List
Local i
For i = 1 To 20
  Friend = New RTSUnit
  CreateFriend(Friend())
Next i

SetFPS 0

//Mouse Stuff
Mouse Off
Global MouseIsDown = False
Dim Selection As BoxInfo

//=============================================================================
//
// MAIN
//
//=============================================================================

Do
  Cls 0

    Text 20, 20, "Left click and drag mouse to select units"
    Text 20, 30, "Right click to select destination for unit to travel to"
    Text 20, 40, "press [SPACE] to randomly reposition all units"

    UpdateFriends()
    DrawAllSprites
    HandleMouse()

    If SpaceKey()
      For Each Friend()
        Friend.Speed = 0
        PositionRandom(Friend())
      Next
    EndIf

  Sync
Loop


//-----------------------------------------------------------------------------
//
//  Handle Mouse
//
//-----------------------------------------------------------------------------
Function HandleMouse()

  //==============================
  //  Handle left button
  //==============================
  If LeftMouseButton()

    If Not MouseIsDown
      //Mouse was just pressed, Initialize Selection box
      Selection.X1 = MouseX()
      Selection.Y1 = MouseY()
      MouseIsDown = True
    EndIf

    //Update and draw bounding box and draw it on screen
    Selection.X2 = MouseX()
    Selection.Y2 = MouseY()
    Box Selection.X1, Selection.Y1, Selection.X2, Selection.Y2, 0

  Else

    If MouseIsDown
      //left mouse button was just released, Select all friend units in the bounding box
      For Each Friend()
        Friend.Selected = PointInBox(Friend.Pos.X, Friend.Pos.Y, Selection.X1, Selection.Y1, Selection.X2, Selection.Y2)
        If Friend.Selected
          SpriteImage Friend.Sprite, FriendSelectedImg
        Else
          SpriteImage Friend.Sprite, FriendImg
        EndIf
      Next
    EndIf

    MouseIsDown = False

  EndIf

  //==============================
  //  Handle right button
  //==============================
  If RightMouseButton()

    Local MX = MouseX()
    Local MY = MouseY()

    //Set destination and speed for each selected friend
    For Each Friend()
      If Friend.Selected
        Friend.Destination.X = MX
        Friend.Destination.Y = MY
        Friend.Direction = GetAngle2D(Friend.Pos.X, Friend.Pos.Y, MX, MY)
        Friend.Speed = Rnd#(1) + 0.5
      EndIf
    Next

  EndIf

  //Draw mouse cursor
Local X = MouseX()
Local Y = MouseY()
CircleC X, Y, 5, 1, purple

EndFunction


//-----------------------------------------------------------------------------
//
//  Update Friends
//
//-----------------------------------------------------------------------------
Function UpdateFriends()

  Local X1, Y1, X2, Y2, Color

  For Each Friend()

    //Stop or move friends have speed > 0
    If Friend.Speed > 0
Local NewX# = CosNewValue(Friend.Pos.X, Friend.Direction, Friend.Speed)
Local NewY# = SinNewValue(Friend.Pos.Y, Friend.Direction, Friend.Speed)
      PositionSprite Friend.Sprite, NewX#, NewY#

      If SpriteHit(Friend.Sprite, GetFirstSprite(), 1)
        PositionSprite Friend.Sprite, Friend.Pos.X, Friend.Pos.Y
      Else
        Friend.Pos.X = NewX#
  Friend.Pos.Y = NewY#
      EndIf

      If (Abs(Friend.Pos.X - Friend.Destination.X) < 3) And (Abs(Friend.Pos.Y - Friend.Destination.Y) < 3)
        Friend.Speed = 0
      EndIf
    EndIf

    If Friend.Selected
      Color = RGB(80, 255, 80)
    Else
      Color = RGB(80, 80, 80)
    EndIf

  Next

EndFunction

//-----------------------------------------------------------------------------
//
//  Position Random
//
//-----------------------------------------------------------------------------
Function PositionRandom(Me.RTSUnit)

  //Make sure randomly placed sprite does not collied with others
  Repeat
    Local X = Rnd(GetScreenWidth())
    Local Y = RndRange(30, GetScreenHeight())
    PositionSprite Me.Sprite, X, Y
  Until Not SpriteHit(Me.Sprite, GetFirstSprite(), 1)

  Me.Pos.X = X
  Me.Pos.Y = Y

EndFunction
//-----------------------------------------------------------------------------
//
//  Handle Friend
//
//-----------------------------------------------------------------------------
Function CreateFriend(Me.RTSUnit)

  Me.Sprite = NewSprite(0, 0, FriendImg)
  PositionRandom(Me())

EndFunction

thaaks

Nice example!

And the code is well written - easy to follow with lots of nice examples on using types and lists and passing types into functions  :)

In UpdateFriends() you still set the local variable Color depending on Friend.selected - I think that's obsolete as you use two different images for the friend sprite. Old code bits from previous versions?

Thanks for sharing it!

Cheers,
Tommy

MudbuG

Thanks for the comments!

You are right about the color command, it is a left-over I forgot to remove.  My first version was done using drawing commands instead of sprites.  UpdateFriends() used CircleC command right after it decided what color to use.  I will go through and clean up these left-overs soon.   

While looking at it again, I also noticed the CreateFriends function has a comment that says it is "Handle Friend".   :o

ATLUS

so nice=) but work time to time=)

thaaks

That's due to the simplified collision handling I guess.
There's no path finding in it (yet?).

As stated by MudbuG in the first post the main reason for this demo was selecting and targeting "friends" with the mouse. And that's working fine.

MudbuG

This is just proof-of-concept.  I certanily would want path finding, and the collision could be tweaked.  My frist version didn't have any collision handling, so all the units eventually ended up on to of each other. 

In this code as it is, when a unit can't get to its destination, it keeps trying to (yeah, in a strait line).  If you select what is in the way and move it, then the first one will continue on its way. 

Here are a few things I have in mind to do later:
* Allow single units to be selected by a mouse click (without drawing a box)
* Add path finding to allow each unit to find the best path to its destination
* Group assignment - select a group and assign a number, then when you press that number the group is selected again.
* Formations - I like groups to move and maintain formation