Moving Multiple Sprites Simultaneously
Moving Multiple Sprites Simultaneously
Moving Multiple Sprites Simultaneously
Moving Multiple Sprites Simultaneously
Moving Multiple Sprites Simultaneously
Moving Multiple Sprites Simultaneously Moving Multiple Sprites Simultaneously Moving Multiple Sprites Simultaneously Moving Multiple Sprites Simultaneously Moving Multiple Sprites Simultaneously Moving Multiple Sprites Simultaneously Moving Multiple Sprites Simultaneously Moving Multiple Sprites Simultaneously
Moving Multiple Sprites Simultaneously Moving Multiple Sprites Simultaneously
Moving Multiple Sprites Simultaneously
Go Back  Xtreme Visual Basic Talk > > > Moving Multiple Sprites Simultaneously


Reply
 
Thread Tools Display Modes
  #1  
Old 06-18-2011, 08:00 PM
CodeCruncher CodeCruncher is offline
Junior Contributor
 
Join Date: Jul 2006
Posts: 355
Default Moving Multiple Sprites Simultaneously


Not wanting to hijack 45minutes thread, I thought I might spawn a thread of my own based on his question.

PlausiblyDamp was kind enough to provide some generic code, which I have modified and attached.

I have made a few alterations mostly around removing random objects, as the game in question (Space Invaders) has a set amount of aliens and set starting positions.

As a start I have limited the “UpdatedPostion” to horizontal movement as the aliens only go side to side unless they hit an edge.

I have added a drop at both sides of the screen, and increase the speed. With a final check to see if you have been invaded.

Now the question....
With “For Each thing In things” it performs UpdatePosition, DropPosition (check), IncreaseSpeed (check), CheckLanded (check) every pass.
I need it to do a simultaneous update on all of the UpdatePosition events.

Something like:
Code:
 Do All thing In Things
thing.UpdatePosition()
End Do
So that all sprites move as one, then do a single check of DropPosition, IncreaseSpeed, CheckLanded
Second Problem... If I move the
thing.DropPosition()
thing.IncreaseSpeed()
thing.CheckLanded()

outside of the For Each thing In things, to run it just once then, it shows error. I need to still get to those checks on Sprite.vb without using the For Each thing In things. Hope the questions make sense.

Code:
    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick 'Form1.vb

        For Each thing In things
            thing.UpdatePosition()
            thing.DropPosition()
            thing.IncreaseSpeed()
            thing.CheckLanded()
        Next
        PictureBox1.Invalidate()

    End Sub

Public Sub UpdatePosition() 'Sprite.vb

        Location += Movement
        If Location.X < 0 OrElse (Location.X + imageSize.Width) > World.WorldSize.Width Then
            Movement = New Point(Movement.X * -1, Movement.Y)
        Else
            Movement = New Point(Movement.X, Movement.Y)
        End If

    End Sub

    Public Sub DropPosition()

        'Dont use + imageSize.Height or it might alter each row of aliens differently based on the height of the alien.
        If Location.X < 0 OrElse (Location.X + imageSize.Width) > World.WorldSize.Width Then Location = New Point(Location.X, Location.Y + 100)

    End Sub

    Public Sub IncreaseSpeed()

        'increase the timer tick amount
        If Location.X < 0 OrElse (Location.X + imageSize.Width) > World.WorldSize.Width Then Form1.Timer1.Interval -= 3

    End Sub

    Public Sub CheckLanded()

        'If landed stop the timer
        If Location.Y + imageSize.Height > World.WorldSize.Height Then Form1.Timer1.Stop()

    End Sub
Attached Files
File Type: zip WindowsApplication1.zip (28.7 KB, 11 views)

Last edited by CodeCruncher; 06-19-2011 at 02:01 AM.
Reply With Quote
  #2  
Old 06-18-2011, 08:13 PM
CodeCruncher CodeCruncher is offline
Junior Contributor
 
Join Date: Jul 2006
Posts: 355
Default

Forgot to mention one of the "gotchas" I came across. When you run the app you will see the bigger icons hit the wall first. I need all the icons to turn around together not to cycle through one by one or the smaller ones will continue to move towards one wall while the bigger ones go towards the other.

They don't really have to move as one block as long as soon as one hits a wall they all change direction. This of course will be diffacult if some have already moved one way before the change of direction takes place.

Almost need a pre check to see if any sprite will hit the wall during the block movement...
Reply With Quote
  #3  
Old 06-18-2011, 08:48 PM
45minutes 45minutes is offline
Regular
 
Join Date: Jan 2011
Posts: 75
Default

hey, I managed to figure this out, but I did it a different way without using loops.

it requires two subs, and the sub that defines the variables in brackets needs to be ByRef, not ByVal. (to actually change the variables outcome), byVal just passes the variable but doesn't give permission to change the variable.

this code is only for the first 4 aliens. If i want more I just add more lines with alien5 variables in the ontimerAlienMove sub. Note all variables still have to be declared at the top of your class.

Code:
    Sub Alienmovementsub(ByRef AlienX As PictureBox, ByRef AlienDirection As String, ByRef AlienSpeed As Integer, ByRef AlienDead As Boolean)
        ' All Alien movement

        Select Case AlienDirection
            Case "Go2Right"
                AlienX.Left += AlienSpeed 'Alien goes right (currently crashes here, says, alienspeed is out of array bounds)
                AlienX.Image = My.Resources.RedAlienSprite1 ' changes image when going right
            Case "Go2Left"
                AlienX.Left -= AlienSpeed 'Alien goes left
                AlienX.Image = My.Resources.RedAlienSprite2 ' changes image when going left
        End Select

        If AlienDead = False Then 'If  alien is still alive then
            If AlienX.Location.X < 20 Then 'The left boundry stop point for current alien.
                AlienDirection = "Go2Right" ' set the current direction string varaible to "Go2Right" 
            End If

            If AlienX.Location.X > 850 Then ' the right boundary stop point for current alien.
                AlienDirection = "Go2Left"  ' set the current direction string varaible to "Go2Left" 
            End If

            If (AlienX.Location.Y < 370 And AlienX.Location.X < 20) Or (AlienX.Location.Y < 370 And AlienX.Location.X > 850) Then ' If current alien location is < 370 on the y axis (approaching ground - still above ground level) Then...
                AlienX.SetBounds(AlienX.Location.X, AlienX.Location.Y + 20, 20, 20) ' Get current alien's dimensions, and drop it by it's own height "20"
                AlienSpeed += 2
            End If
        End If

    End Sub


    Sub ontimerAlienMove()

        Alienmovementsub(Alien1, Alien1Dir, alien1speed, Alien1Hit)
        Alienmovementsub(Alien2, Alien2Dir, alien2speed, Alien2Hit)
        Alienmovementsub(Alien3, Alien3Dir, alien3speed, Alien3hit)
        Alienmovementsub(Alien4, Alien4Dir, alien4speed, alien4hit)

    End Sub
In other words, anything in ontimerAlienMove sub will be executed by all if .. end if conditions in Alienmovementsub. Each variable name in ontimerAlienMove e.g. Alienmovementsub(Alien1, Alien1Dir, alien1speed, Alien1Hit) is substituted for its respective variable in Alienmovementsub(ByRef AlienX As PictureBox, ByRef AlienDirection As String, ByRef AlienSpeed As Integer, ByRef AlienDead As Boolean).

Hope that helps.
Reply With Quote
  #4  
Old 06-18-2011, 10:13 PM
CodeCruncher CodeCruncher is offline
Junior Contributor
 
Join Date: Jul 2006
Posts: 355
Default

I think I follow what you are trying to do, you are creating each alien independantly with its own parameters...

I like what PlausiblyDamp has done with the whole List thing (basically an undefined array).

I just made a quick mod to the code I posted earlier to add an alien active status like this...
s.Active = Boolean.TrueString 'Initially sets all aliens as active / alive

That way the active / dead status is an element of the alien rather than a seperate variable.

I am also trying to step up my coding by using classes and by making it a member of the sprite so it groups it to the same class.

As a property of the sprite (s) I can easily call on it to see if it is active, if it is draw it, if it isn't don't.

Code:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        Dim blnAlt As Boolean
        Dim iLocX As Integer
        Dim iLocY As Integer

        For i1 As Integer = 0 To 1 'Move next row of aliens right
            iLocX += 100
            For i2 As Integer = 0 To 1 'Move next alien down
                iLocY += 100
                Dim s As Sprite

                If blnAlt = True Then 'alternate the images
                    s = New Sprite(My.Resources.logo)
                    blnAlt = False
                Else
                    s = New Sprite(My.Resources.Untitled)
                    blnAlt = True
                End If
                s.Location = New Point(iLocX, iLocY) 'Set various starting postions
                s.Movement = New Point(30, 0) 'Move horizontally
                s.Active = Boolean.TrueString 'Initially sets all aliens as active / alive <<<< NEW LINE HERE
                things.Add(s)
            Next
            iLocY = 0 'Reset ready for next pass
        Next

    End Sub
Reply With Quote
  #5  
Old 06-18-2011, 10:40 PM
CodeCruncher CodeCruncher is offline
Junior Contributor
 
Join Date: Jul 2006
Posts: 355
Default

Essentially what you have done is very similar to the List method except you have to manually create each new sprite whereas PB’s list is dynamic.

Just thinking about the Alien Direction and Speed since all alien direction and speeds should be the same is it really necessary to make that an attribute of your alien?

Also isn't speed controlled by your Timer_Tick event? So the increase of speed is only applicable to it not the specific alien.

Code:
Sub ontimerAlienMove()

        Alienmovementsub(Alien1, Alien1Dir, alien1speed, Alien1Hit)
        Alienmovementsub(Alien2, Alien2Dir, alien2speed, Alien2Hit)
        Alienmovementsub(Alien3, Alien3Dir, alien3speed, Alien3hit)
        Alienmovementsub(Alien4, Alien4Dir, alien4speed, alien4hit)
Sub
If so I could easily add Direction if that help change direction of all my aliens at the same time...

Code:
                s.Location = New Point(iLocX, iLocY) 'Set the various starting postions
                s.Movement = New Point(30, 0) 'Move horizontally by this much
                s.Active = Boolean.TrueString 'Initially sets all aliens as active / alive
                s.Direction = Boolean.TrueString 'Use boolean True or False for left and right control
                things.Add(s)
Reply With Quote
  #6  
Old 06-18-2011, 11:25 PM
passel's Avatar
passelMoving Multiple Sprites Simultaneously passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 8,024
Default

I thought PlausiblyDamp's code was in VB.
The "WindowsPhoneApplication1.zip" you attached appears to be C# and won't load on my machine. Perhaps you have a version of "WindowsApplication1.zip" that you meant to attach.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
Reply With Quote
  #7  
Old 06-19-2011, 02:03 AM
CodeCruncher CodeCruncher is offline
Junior Contributor
 
Join Date: Jul 2006
Posts: 355
Default

I attached the wrong file by mistake... updated first post with correct VB file.
Reply With Quote
  #8  
Old 06-19-2011, 04:12 PM
PlausiblyDamp's Avatar
PlausiblyDampMoving Multiple Sprites Simultaneously PlausiblyDamp is offline
Ultimate Contributor

Forum Leader
* Expert *
 
Join Date: Nov 2003
Location: Newport, Wales
Posts: 2,058
Default

Just had a quick look at the code and a couple of things got my attention...

Firstly I noticed you added a Direction property to the sprite but you have kept the Movement property as well, this effectively is giving you two ways or managing one thing (direction of travel). Personally I would pick one or the other but not both, having to track the same thing twice increases the chance of a bug creeping in.

I also notice you made the Direction property a Boolean but you seem to be assigning a value to it in a strange way e.g. you are doing
Code:
s.Active = Boolean.TrueString
which is actually using a string, you would normally assign a Boolean using the more straightforward
Code:
s.Active = True
You really should add Option Strict On to the top of your source files to help catch VB's automatic type conversion.

I would also either give the Direction property a more meaningful name (after all to someone reading the code what does Direction = False mean?) or do as Atma suggested over here http://www.xtremevbtalk.com/showpost...82&postcount=5 and use an enumeration instead.

Rather than add an Active property to the sprite and use this to decide if the sprite needs processing or not you could simply remove inactive sprites from the list (one of the benefits of the List class is you can remove things from it) - this way all items in the list get processed and if an invader is destroyed then it is removed from the list.

I would also change the
Code:
Public Sub CheckLanded()

        'If landed stop the timer
        If Location.Y + imageSize.Height > World.WorldSize.Height Then Form1.Timer1.Stop()

    End Sub
method to simply return true or false depending on if the Alien has reached the bottom e.g.
Code:
Public Function CheckLanded() as Boolean

        Return (Location.Y + imageSize.Height) > World.WorldSize.Height 

    End Sub
and let the Timer itself decide what to do when an alien has landed e.g.
Code:
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick

        For Each thing In things
            thing.UpdatePosition()
            thing.DropPosition()
            thing.IncreaseSpeed()
         if   thing.CheckLanded() then
            timer1.Stop()
         end if
        Next
        PictureBox1.Invalidate()

    End Sub
__________________
Intellectuals solve problems; geniuses prevent them.
-- Albert Einstein

Posting Guidelines Forum Rules Use the code tags
Reply With Quote
  #9  
Old 06-19-2011, 09:19 PM
CodeCruncher CodeCruncher is offline
Junior Contributor
 
Join Date: Jul 2006
Posts: 355
Default

Direction and Movement… I thought about this for a moment before adding it, but decided that movement only told it to move by a given amount not which direction to move (unless you take negative numbers into account).

But really after giving it more thought I’m not sure it is really necessary as all sprites need to change direction at the same time, it’s not like they are weaving around the screen.

s.Active = Boolean.TrueString
Not sure why I did this, I thought I was declaring it as a Boolean, but I have done that elsewhere, so yes it was a strange thing to do.

“You really should add Option Strict” yep will do

AtmaWeapon Said:
What's AlienDirection? It's an enum I made up:
Code:
Public Enum AlienDirection
Left,
Right
End Enum

I have never used an Enumeration before; the word Enum is a bit scary (probably just means add numbers to an array… or something equally simple), but simple or not I don’t know how to use it.

“Rather than add an Active property to the sprite and use this to decide if the sprite needs processing or not you could simply remove inactive sprites from the list”

Yes that would be the smart thing to do since each sprite has its own location built in, all I need to do is move it relative to its start position, and it won’t matter that the sprite next to it has been destroyed.
Reply With Quote
  #10  
Old 06-20-2011, 04:24 AM
CodeCruncher CodeCruncher is offline
Junior Contributor
 
Join Date: Jul 2006
Posts: 355
Default

Update code to include suggestions.

Still struggling with this... 'things.All(Function(thing) UpdatePosition = True)

Not really sure what I'm doing, but I'm trying to move all the sprites at once so if I need to change direction I can do it with one command.
Attached Files
File Type: zip WindowsApplication1.zip (31.7 KB, 5 views)
Reply With Quote
  #11  
Old 06-20-2011, 12:33 PM
passel's Avatar
passelMoving Multiple Sprites Simultaneously passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 8,024
Default

Perhaps you don't have the logic quite right yet.
Essentially, all the aliens should move in the same direction, and they should only move in one of three directions per major frame of action, left, right or down.
Which direction they will move in the next frame is determined by the movement in the current frame.
If they are moving right in the current frame and any one of them comes in contact with the right edge, the movement in the next frame will be down.
If they are moving down in the current frame and any one of them comes in contact with the ground, the round is over, else the next frame they will move away from the edge they are currently on.
If they are moving left in the current frame and any one of them comes in contact with the left edge, the movement in the next frame will be down.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
Reply With Quote
  #12  
Old 06-21-2011, 04:50 AM
CodeCruncher CodeCruncher is offline
Junior Contributor
 
Join Date: Jul 2006
Posts: 355
Default

Yes definitely struggling to get the idea to code... What you describe is what I am trying to do but the thing I am having the most problem with is getting the aliens to move as a block... I can have them cycle through one at a time like they currently are but it doesn’t produce the result I am looking for.

By modifying them one by one I might get half way through moving them forward when one hits a boundary and turn it around throwing everything out of sync.

It’s like I need to pre check to see if it’s going to hit a boundary before I get any of them to move. There no issue moving them one by one if I know it’s not going to hit anything, or if it is going to hit a wall that I turn them all around from the start.

But how do I do a check see if it is going to hit a wall without actually moving them?
Reply With Quote
  #13  
Old 06-21-2011, 05:44 AM
PlausiblyDamp's Avatar
PlausiblyDampMoving Multiple Sprites Simultaneously PlausiblyDamp is offline
Ultimate Contributor

Forum Leader
* Expert *
 
Join Date: Nov 2003
Location: Newport, Wales
Posts: 2,058
Default

I have added an updated version of your last attachment to this post....

The main differences are ....
Code:
    'Simply reverses the direction of movement along the X-Axis
    Public Sub ChangeDirection()
        Movement = New Point(Movement.X * -1, Movement.Y)
    End Sub

    'Will return true if either edge reached
    Public Function CheckEdgeReached() As Boolean
        Return Location.X < 0 OrElse (Location.X + imageSize.Width) > World.WorldSize.Width
    End Function
These two methods have been added to the sprite class, we will let the sprite look after it's direction and it decides if an edge has been reached or not. I have also simplified the UpdatePosition code to be just
Code:
    Public Sub UpdatePosition()
        Location += Movement
    End Sub
now the ChangeDirection method takes care of the direction we no longer need to worry about it while moving.

The Timer1_Tick event has been modified to look like
Code:
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick

        'used to track if anything has reached an edge...
        Dim edgeReached As Boolean

        'Get each thing to update it's position and report if it reached an edge
        For Each thing In things
            thing.UpdatePosition()

            If thing.CheckEdgeReached() Then
                edgeReached = True
            End If
        Next

        'If an edge was reached then we need to move down, change direction
        'and increase the speed if game continuing or stop the timer if game is over.
        If edgeReached Then
           Timer1.Interval -= 3 
            For Each thing In things
                thing.DropPosition()

                If thing.CheckLanded() Then
                    Timer1.Stop()
                Else         
                    thing.ChangeDirection()
                End If
            Next
        End If
        
        PictureBox1.Invalidate()

    End Sub
It now effectively takes two passes over the sprites, one to update the position of each sprite and to record if any of them have hit an edge.

If no edge has been hit then we continue as normal. If an edge has been reached then we cause the aliens to move down, change direction and increase the speed. We also take this opportunity to see if they have reached the bottom and if so stop the timer.
Attached Files
File Type: zip WindowsApplication1.zip (27.6 KB, 10 views)
__________________
Intellectuals solve problems; geniuses prevent them.
-- Albert Einstein

Posting Guidelines Forum Rules Use the code tags

Last edited by PlausiblyDamp; 06-21-2011 at 06:16 AM.
Reply With Quote
  #14  
Old 06-23-2011, 06:09 AM
CodeCruncher CodeCruncher is offline
Junior Contributor
 
Join Date: Jul 2006
Posts: 355
Default

I was getting there but I was having issues getting it to return a value from sprite.vb, I tried sending a variable to then have it updated, but it wasn’t working. It was just two variables with the same name.

I see you sort of did the same thing but got the result I couldn't... You had the Boolean return a value like I did in PreCheck below, but you didn’t try to set it to anything in Form1, but you did use the value it returned.

Code:
            If thing.CheckEdgeReached() Then
                edgeReached = True
            End If
It would seem that Form1 still gets the value that was set in Sprite.vb like the example above. I think I just found the missing step to returning a value from another Class.

Code:
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick

        Dim blnFlag As Boolean
        For Each thing In things
            thing.PreCheck(blnFlag)
        Next

        'If blnFlag = True Then
        '    blnFlag = False
        'For Each thing In things
        '    thing.DropPosition()
        'Next
        'End If

        For Each thing In things
            thing.UpdatePosition()
        Next

        'End If

        'For Each thing In things
        '    thing.UpdatePosition()
        '    thing.DropPosition()
        '    thing.IncreaseSpeed()
        '    If thing.CheckLanded() Then
        '        Timer1.Stop()
        '    End If
        'Next
        PictureBox1.Invalidate()

    End Sub
Code:
    Public Property blnFlag As Boolean

    Public Sub PreCheck(ByVal blnFlag As Boolean)

        Location += Movement
        If Location.X < 0 OrElse (Location.X + imageSize.Width) > World.WorldSize.Width Then
            blnFlag = True
            Exit Sub
        End If

    End Sub
Reply With Quote
  #15  
Old 06-23-2011, 06:48 AM
PlausiblyDamp's Avatar
PlausiblyDampMoving Multiple Sprites Simultaneously PlausiblyDamp is offline
Ultimate Contributor

Forum Leader
* Expert *
 
Join Date: Nov 2003
Location: Newport, Wales
Posts: 2,058
Default

If you want to return a value then simply use a Function rather than a Sub, it is exactly the reason functions exist.

In your code
Code:
Public Property blnFlag As Boolean

    Public Sub PreCheck(ByVal blnFlag As Boolean)

        Location += Movement
        If Location.X < 0 OrElse (Location.X + imageSize.Width) > World.WorldSize.Width Then
            blnFlag = True
            Exit Sub
        End If

    End Sub
the public property blnFlag would be hidden by the parameter blnFlag anyway and probably still wouldn't do what you intend. I wouldn't add a member to a class just to allow a single method on the class return a value anyway, simply make the sub into a function and return the value from the function.
__________________
Intellectuals solve problems; geniuses prevent them.
-- Albert Einstein

Posting Guidelines Forum Rules Use the code tags
Reply With Quote
  #16  
Old 06-23-2011, 08:07 PM
CodeCruncher CodeCruncher is offline
Junior Contributor
 
Join Date: Jul 2006
Posts: 355
Default

Thank you vey much for your assistance PlausiblyDamp it is greatly appreciated, it is often the simple things that consume so much of your time. Now that I have a better understanding of how to pass data between classes I won’t be so scared to use them more freely and where appropriate, rather than trying to cram everything into Form1.
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Forum Jump

Advertisement:





Free Publications
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET.
subscribe
Programmers Heaven C# School Book -Free 338 Page eBook
The Programmers Heaven C# School book covers the .NET framework and the C# language.
subscribe
Build Your Own ASP.NET 3.5 Web Site Using C# & VB, 3rd Edition - Free 219 Page Preview!
This comprehensive step-by-step guide will help get your database-driven ASP.NET web site up and running in no time..
subscribe
Moving Multiple Sprites Simultaneously
Moving Multiple Sprites Simultaneously
Moving Multiple Sprites Simultaneously Moving Multiple Sprites Simultaneously
Moving Multiple Sprites Simultaneously
Moving Multiple Sprites Simultaneously
Moving Multiple Sprites Simultaneously Moving Multiple Sprites Simultaneously Moving Multiple Sprites Simultaneously Moving Multiple Sprites Simultaneously Moving Multiple Sprites Simultaneously Moving Multiple Sprites Simultaneously Moving Multiple Sprites Simultaneously
Moving Multiple Sprites Simultaneously
Moving Multiple Sprites Simultaneously
 
Moving Multiple Sprites Simultaneously
Moving Multiple Sprites Simultaneously
 
-->