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
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
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
so nice=) but work time to time=)
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.
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