Control Arrays

Danjb
10-03-2009, 11:23 AM
Hey,

This is another question I've always wondered about. If you make a control array, is there a way you can reference "any" object in the array?

For instance, if there are 3 moving objects in an array and I want to check when any one of them reaches a certain point? Previously I've used a variable "i" and checked "Object.i", then "Object.i+1", etc. but it's very long winded and seems unnecessary.

In addition, is there a way to check WHICH object in the array had reached said point?

Thanks,

- Danjb

Iceplug
10-03-2009, 11:48 AM
The main reason to add things to a control array is so that you can easily loop through them...
example - add three labels to your form, change all names to Labelset:

Dim LV As Integer
For LV = 0 To 2
Labelset(LV).Caption = "Howdy"
Next

To check if any element in a control array reaches, say, the left end of the form.
Dim Done As Boolean
Do Until LV = 3 Or Done
If Labelset(LV).Left <= 0 Then
Done= True
End If
LV = LV + 1
Loop
Or you could consolidate the entire If block into
Done = (Labelset(LV).Left <= 0)
The right end is Labelset(LV).Left + Labelset(LV).Width >= Me.Scalewidth
And, with the Do Loop, the value of LV will indicate which label has reached the end - or if LV = 3 then neither have reached the end.
:)
You just have to set it up for your customization.

Danjb
10-03-2009, 04:09 PM
Thanks - I think my main overall problem is I'm just lacking so many little tricks, like in your line: "Done = (Labelset(LV).Left <= 0)".

As for the control arrays - what you showed me is similar to what I came up with myself, although I didn't know about using "For", as in: "For LV = 0 To 2", and I'm not too familiar with the Loop command (though I really should be...).

However, the problem I had was that, with a lot of objects, I ended up getting a lot of lag... which seems ridiculous for just a simple VB program.

It may be that I can get rid of the lag just by improving my old code, i.e. by using For or Loop. Previously I think I had a Goto...

I hoped there might be a way to ignore the index of a control array completely, so rather than checking whether Object(1), Object(2) or Object(3) have reached the wall you can just check whether any Object has reached the wall.

But I guess not?
And any ideas about the lag?

Thanks,

- Danjb

claus1958
10-04-2009, 12:47 AM
Hi Danjb,

to detect the lag we have to see the code you're using ...

But one thing - the objects are not moving by themself - instead your code moves them. In doing this you could checkout i they have reached the wall. In the routine where you set the position you can set a flag like 'reachedthewall'. Or you can put the indexes of all 'reachedthewall' object in an array - so you dont have to loop through ALL the objects each time. Many ways ...
Cheers Claus

Danjb
10-05-2009, 11:45 AM
Thanks.

Here's where you regret asking for the code ;)

Ok, basically there are five types of "gem fiend" of different colours. There are multiple gem fiends of each colour in a control array, as well as 4 timers for each colour (so 20 timers in total).

===================================

One of the timers controls movement - here's the code.

"i" is a variable that controls which gem fiend of the control array the timer is referring to.

"r" is a randomized variable that determines how the gem fiend moves.
The Tag of the gem fiend is the angle at which they move.

"n" and "E" are strings passed on to functions to specify which type of gem fiend is being manipulated. The two functions move the gem fiends (EnemyMove) and, if necessary, change the image to show which way the gem fiend is facing (TurnPicture).

Private Sub Enemy1Move_Timer()

Dim i
i = 1

Dim r

Reepeet:
r = Int(Rnd * 10)
If (i < Enemy1.Count) Then
If (r <= 5) Then
If (Enemy1(i).Tag >= 360) Then
Enemy1(i).Tag = 10
Else
Enemy1(i).Tag = Val(Enemy1(i).Tag + 10)
End If
ElseIf (r <= 10) Then
If (Enemy1(i).Tag <= 0) Then
Enemy1(i).Tag = 350
Else
Enemy1(i).Tag = Val(Enemy1(i).Tag - 10)
End If
End If
Dim n As String
n = 1
Call EnemyMove(i, n)
Dim E As String
E = "E"
Call TurnPicture(Enemy1(i), E, 1)
i = Val(i + 1)
GoTo Reepeet
Else
i = 1
End If

End Sub

===================================

The second timer detects when one of the gem fiends hits "Spyro", controlled by the user.

"i" is again a variable to show which gem fiend of the control array is being affected.

"EnemyHitAgain" is a timer to ensure a delay between two hits.

Private Sub Enemy1Hit_Timer()

Dim x1
Dim y1
Dim x2
Dim y2

Dim i
i = 1

RinseRepeat:
If (i < Enemy1.Count) Then
x1 = Spyro.Left
y1 = Spyro.Top
x2 = Enemy1(i).Left
y2 = Enemy1(i).Top

If ((x2 - 300) < x1) And ((x2 + 400) > x1) Then
If ((y2 - 300) < y1) And ((y2 + 400) > y1) Then
If (Jump.Enabled = False) Then
Call SparxDamage
PlaySoundA App.Path & "\Sounds\Hit.wav", 0, 1 'Sound
Enemy1Hit.Enabled = False
EnemyHitAgain.Enabled = True
End If
End If
End If
i = Val(i + 1)
GoTo RinseRepeat
Else
i = 0
End If

End Sub

===================================

The third timer makes gem fiends drop gems every few seconds (up to a limit). Each colour of gem fiend has their own colour of gem. Each gem then has another timer to detect when Spyro runs it to it to "collect" it.

Private Sub Enemy1Gems_Timer()

'Every 3 seconds, make enemies drop 3 gems
If (Enemy1Gems.Tag >= 3) Then
Dim i
i = 1
AndAgain:
If (i < Enemy1.Count) Then
Dim x
Dim y
x = Val(Enemy1(i).Left - 250)
y = Val(Enemy1(i).Top - 250)
Call GemRedSpawn(x, y, 3)
i = Val(i + 1)
GoTo AndAgain
End If
Enemy1Gems.Tag = 0
Else
Enemy1Gems.Tag = Val(Enemy1Gems.Tag + 1)
End If

End Sub

===================================

The fourth timer spawns more gem fiends (up to a limit).

Private Sub Enemy1Spawn_Timer()

'If less than 1 enemies, spawn one after 10 seconds
If (Enemy1.Count < 2) Then
If (Enemy1Spawn.Tag >= (10 * Enemy1.Count)) Then
Call EnemySpawn(1, Enemy1.Count)
Enemy1Spawn.Tag = 1
Else
Enemy1Spawn.Tag = Val(Enemy1Spawn.Tag + 1)
End If
End If

End Sub

===================================

So!
To sum up...

Clearly the code could use a LOT of improvement, and uses a LOT of timers.

I'd really appreciate any help with it, and if you want the code for any of the functions mentioned, let me know.

Thanks,

- Danjb

Iceplug
10-05-2009, 02:17 PM
Hmm - I wouldn't regret asking for the code - looks like we can do some overhauling here :p
First of all, put some declarations on your variables! Is Option Explicit on?
Dim i As Integer
i = 1

Dim r As Integer

And also:
Dim n As String 'Why declare this as string?
n = 1 'When you turn around and put an integer into it?

And also, you use Goto?
I strongly recommend using a Do Loop or For Loop instead.
Your first and second timer codes currently have the following layout (or similar, maybe one of the lines aren't there in the second one, I used the first one as an example):

'some code we'll refer to as (A)
Reepeet:
'a line of code we'll refer to as (B)
If (i < Enemy1.Count) Then
'some lines of code we'll refer to as (C)
i = Val(i + 1)
GoTo Reepeet
Else
'the line of code we'll refer to as (D)
End If

Your code will run the same without Goto in the following layout:

'some code we referred to as (A)
'the line of code we referred to as (B)
Do While (i < Enemy1.Count)
'some lines of code we referred to as (C)
i = Val(i + 1)
'the line of code we referred to as (B)
Loop
'a line of code we referred to as (D)

Please declare as Integer or as Long:
Dim x1
Dim y1
Dim x2
Dim y2
I suppose I could also ask why you use Val in the line
i = Val(i + 1)
when i must be a number to begin with?
Enemy1Gems three - another Goto to be eliminated:

If (Enemy1Gems.Tag >= 3) Then
'code (A)
AndAgain:
If (i < Enemy1.Count) Then
'code (B)
i = Val(i + 1)
GoTo AndAgain
End If
'code (C)
Else
'code (D)
End If

can become

If (Enemy1Gems.Tag >= 3) Then
'code (A)
Do While (i < Enemy1.Count)
'code (B)
i = Val(i + 1)
Loop
'code (C)
Else
'code (D)
End If
Regardless of what you have inside the code for your timers, I'm sure you can remove some of these timers by combining the code in timers with equivalent intervals and use Boolean variables.
Each gem then has another timer to detect Oh dear...
Well, if you find two (or three, four, or however many) timers with the same interval, you can combine them at the cost of creating boolean variables.
Let's assume you have two timers on your form with the same interval - one called TimerA and another called TimerB:

Private Sub TimerA_Timer()
'TimerA's code.
End Sub

Private Sub TimerB_Timer()
'TimerB's code.
End Sub

Combine two timers into one by doing this:

Dim TimerAEnabled As Boolean, TimerBEnabled As Boolean 'You can change this name to something more meaningful
Private Sub TimerA_Timer()
If TimerAEnabled Then
'TimerA's code.
End If
If TimerBEnabled Then
'TimerB's code.
End If
'Now, you can delete TimerB from the form...
'you'll also have to change all references to TimerB.Enabled to TimerBEnabled
'(without the period)

I think my main overall problem is I'm just lacking so many little tricksThat one you are referring to is not something you should be overly concerned with - that's just execution timesaving stuff. I hope the above has helped make your code easier to follow and closer to identifying the problem. So, one more question - how many enemy1's are there?

Danjb
10-08-2009, 10:39 AM
Hmm - I wouldn't regret asking for the code - looks like we can do some overhauling here
Heh, too right! Thanks a lot for being so willing to help :)

First of all, put some declarations on your variables! Is Option Explicit on?
Ok, I've sorted out the declarations now :)
For the ones that weren't integers I put "Dim ... As Double" - is that ok? I tried first as Long but it went a bit wrong...
Does it really make that much of a difference?
No, I've never really understood Option Explicit...

Dim n As String 'Why declare this as string?
n = 1 'When you turn around and put an integer into it?
Heh, I guess because it later became part of a string, but I've changed it now.

And also, you use Goto?
I strongly recommend using a Do Loop or For Loop instead.
Yeah, my VB knowledge was / is pretty limited so I just used a method I knew. Thanks, I've changed it to a loop. Things seem to be running much smoother already!

I suppose I could also ask why you use Val in the line
i = Val(i + 1)
when i must be a number to begin with?
That's because I used to have trouble with adding text boxes, i.e. 3 + 3 = 33 but I guess that's because they were being treated as strings but the problem wouldn't occur here.
I've now deleted the "Val" off every statement except ones that used a Tag property as I thought that might need it...?

Enemy1Gems three - another Goto to be eliminated
Thanks - done!

Regardless of what you have inside the code for your timers, I'm sure you can remove some of these timers by combining the code in timers with equivalent intervals and use Boolean variables.
I hoped I might be able to do something like that...
Thanks, I'll give it a shot.
Might there be any even better way that gets rid of the timers and a LOT of code?
A lot of the code is exactly the same just with a different numbered enemy, i.e. Enemy1, Enemy2, etc...
Might take a fair bit of work though...?

That one you are referring to is not something you should be overly concerned with - that's just execution timesaving stuff. I hope the above has helped make your code easier to follow and closer to identifying the problem.
Ok, thanks. I'm definitely learning anyway :)
Yeah, definitely, thanks a lot for all your help, I really appreciate it. I could have done with finding a VB forum like this a long time ago! ;)

So, one more question - how many enemy1's are there?
At the moment there is just 1 enemy1, the idea being that as you collect gems you can buy more, as well as other types of enemies.
I think I was aiming for something like 5 enemy1s, 4 enemy2s, 3 enemy3s, 2 enemy4s and 1 enemy5. However, the higher numbered enemies drop gems a lot less frequently.

Iceplug
10-08-2009, 07:12 PM
For the ones that weren't integers I put "Dim ... As Double" - is that ok? I tried first as Long but it went a bit wrong...
Does it really make that much of a difference?
No, I've never really understood Option Explicit...

Well, if you declare it as Double, then it will work, but if you aren't going to put floating point or if you aren't using .Left or .Top members with the variable then it is better suited to be Integer or Long.

Option Explicit raises a message if you use a variable that is not declared - the purpose is to identify misspelled variable names which would, instead of getting the expected value, generate a new blank variable with the misspelled name.


I've now deleted the "Val" off every statement except ones that used a Tag property as I thought that might need it...?

Well, yes, that would be a reason to keep Val(), but the proper usage is:
Thing.Tag = Val(Thing.Tag) + 1
or, if you're really a stickler for conversion,
Thing.Tag = CStr(Val(Thing.Tag) + 1)
though I don't bother with the latter.
A lot of the code is exactly the same just with a different numbered enemy, i.e. Enemy1, Enemy2, etc...
Might take a fair bit of work though...?

To consolidate all of the enemies would require some sort of array, which would require detailed analysis to convert the existing code to work with arrays.

Danjb
10-09-2009, 06:14 AM
Well, if you declare it as Double, then it will work, but if you aren't going to put floating point or if you aren't using .Left or .Top members with the variable then it is better suited to be Integer or Long.
I don't know what floating point means but some lines were using .Left and .Top, so I've kept those ones as Double but changed the others to Long.

Option Explicit raises a message if you use a variable that is not declared - the purpose is to identify misspelled variable names which would, instead of getting the expected value, generate a new blank variable with the misspelled name.
I see. I'll add it in. Is it only really useful for testing then?

And also, what are the advantages of declaring your variables "As" something? I mean, what's the harm in leaving that part out?

Well, yes, that would be a reason to keep Val(), but the proper usage is:
Thing.Tag = Val(Thing.Tag) + 1
Fixed.

To consolidate all of the enemies would require some sort of array, which would require detailed analysis to convert the existing code to work with arrays.
Ok, I'll perhaps look into that a little later.

Thanks for all your help.

I have plenty of other questions, but should I post them here or in separate threads? Some are related to this game, some are just general questions and some are for other games...

vb5prgrmr
10-10-2009, 01:19 AM
And also, what are the advantages of declaring your variables "As" something? I mean, what's the harm in leaving that part out?


Leaving variables "undeclared" (not "as" something) makes them varients and can cause errors but will definitly slow down your code because vb would first need to attempt to interprete what kind of variable type it is before it can do any type of operation or assignment with that variable.

As for Option Explicit...VB's IDE Menu>Tools>Options>Put check next to Require Variable Declaration on the Editor Tab>OK.



Good Luck

Danjb
10-12-2009, 11:48 AM
Thanks, that's just what I wanted :)

EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum