Jump to content
m0nkey

Understanding arma arrays - coming from other languages

Recommended Posts

Hello.

I'm just your typical hardcore geek who knows a little about a lot, but not enough about arma scripting. Trying to bring myself up to speed as it were.

One thing that is pretty different in arma, compared to basic script languages like vb or autoit (lets not even get into dos/batch lol) is the array.

Its typical to init an array - _myArr = [];

and to init with values - -myArr = ['boy','girl','dog'];

and also fairly typical in the forEach loop and even the less popular for "_i" type loops. I've used all these. I understand what arrays are, etc etc.

In looking at the code optimisation page, I can see right away how you can append a value in the fastest method by using set and count. Its easy to understand, set will set the value at an index. And when used in conjunction with count its saying, in a basic form

$array = ['one','two','three']
$array[ubound($array)] = 'new value'

Which is just not subtracting 1 from the last index value, like you would do if you were going to step through an array with a loop. Its also redim'ing the array at the same time by +1

But I also see that count is faster than forEach, when stepping through arrays. The reserved variable _x will reference the "value" of the current index in the stepping. forEach actually gives you the indice if you want it. But for sake of creating optimized code, here is an example I have been struggling with. Its of no bearing other than its something I chose to play with.

define an array of squad mates

_squadpeeps = group player;

define an array publicly

arr_livepeeps = [];

now the goal is to step through the array of members of squad, see who is alive and not the player, then add/append them to the blank array. Something like this:

{
  if (alive _x and _x!=player) then {arr_livepeeps set [count arr_livepeeps, _x];};
} forEach units _squadpeeps;

this appear it would step though the members of the group, referencing _x and if alive and not player, resize the array by +1 and put the object handle to the player in the array (I think its an object handle anyway).

What I don't get is how to use count in such a situation. I see count as having one function, to return a count, although it does reference _x.

So you can: _var = count _array;

_var = {_x == 'boy'} count _array:

But I don't get how to use count rather than forEach.

This is strictly academic. I've a fast computer and noticed that some maps/missions are so slow that my fast computer seems like a turd. Reading and experimenting show me too many objects at once, misconfigured servers and too many scripts or too heavy scripts or just scripts that aren't optimized seem to be the main culprits.

So, since I am sick and tired of the way other FPS games are going, I'd like to figure out how to make my own missions in arma for me and my buds that don't suck the performance out of our machines and kill the experience. Thus, time to learn arma script language, and frankly I've too much experience to just copy/paste blindly. I know how much little bits of optimization can help.

Anyone care to teach a noob?

PS: where is the best resource for how arma is actually doing things, like what files/scripts are loaded first, order of events etc, and a guide for how to properly code multiplayer missions to properly utilize the order of events, things of that nature. Arma is so spread out its quite frustrating finding good infos ;)

Share this post


Link to post
Share on other sites

Answer is easy and is in the commands name already:

foreach is foreach: itinerating through al elements.

count is count: it counts something (which is needed many times in Arma coding, so this is handy)

The best resource? Trial and error and testing. If you start coding, you will run into all problems one time: you can search the forums on the topic, and it will give you an answer for sure. I've been through this, it took my like 3 years though. :)

http://forums.bistudio.com/showthread.php?100559-Beginners-guide-Arrays

http://community.bistudio.com/wiki/Array

http://killzonekid.com/arma-scripting-tutorials-arrays-part-1/

(browse all of KK's tutorials. They rock)

http://community.bistudio.com/wiki/Code_Optimisation

The main performance eater is AI. So if a mission places all AI that it uses on the map, it may kill performance. Unit caching is a good solution on the long run. So you always got to minimize AI on the map.

The other is that you need to know the performance of each commands. There are heavy commands, and light ones. This is experience. Use BIS' performance tools and measure all your commands.

Edited by zapat

Share this post


Link to post
Share on other sites

Thank you for replying. Actually I have seen all of those resources. Over and over it seems lol.

My questions stemmed from these

Adding elements to an array

set is around 2x faster than binary addition

_a set [count _a,_v]

Instead of:

_a = _a + [_v]

and

forEach vs count

Both commands will step through supplied array of elements one by one and both commands will contain reference to current element in _x variable. However count loop is a little faster than forEach loop, but it does not have _forEachIndex variable.

{diag_log _x} count [1,2,3,4,5,6,7,8,9];
//is faster than
{diag_log _x} forEach [1,2,3,4,5,6,7,8,9];

_someoneIsNear = {_x distance [0,0,0] < 1000} count allUnits > 0;
//is still faster than
_someoneIsNear = {
if (_x distance [0,0,0] < 1000) exitWith {true};
false
} forEach allUnits;

So, while I understand arrays and how to manipulate them, I don't understand how to apply using count in place of forEach in my example. Maybe you cannot, which is what I am trying to figure out.

I am interested in this because, as I learn the arma scripting language, I want to start with good habits. Sometimes its the simple small things that can make the biggest differenct. The best example I've actually used would be in one language, when you concatenate you traditionally would use

i = i + 1

while this is quite acceptable, there are crazy performance increases by using this instead

i += 1

granted we're talking about several hundred elements in an array or parsing a text document, but learning these little "secrets" about what is the optimal methods to use is what I am trying to learn.

Thanks.

edit:

would it be something like this?

{
  if (alive _x and _x!=player) then {arr_livepeeps set [count arr_livepeeps, _x];};
} count units _squadpeeps;

where the stepping of _x comes as count goes through each "units" of array "_squadpeeps"? Thats pretty simple if its the answer. Of course, count vs forEach might not be enough performance difference to worry about, but gotta learn what you can I suppose :)

Edited by m0nkey

Share this post


Link to post
Share on other sites

You can't use count INSTEAD of foreach.

You can use count if you would COUNT something WITH FOREACH.

hint str  ({alive _x} count (group player));

will give you eg. 5.

easier and faster than

_cnt = 0;
{
   if (alive _x) then {_cnt = _cnt + 1};
} foreach (group player);
hint str _cnt;

You cannot manipulate but only count with count! It comes handy in eg. FSM conditions, which is a time-sensitive place, where it is good to have a lightweight solution for a very usual job.

You are right about having to learn each small tricks: one small difference is one small difference. But this small difference multiplied can lead to huge differences.

Edited by zapat

Share this post


Link to post
Share on other sites

Hmm. Understood. In the interest of understanding this, might I pose a further question?

Your example

hint str  ({alive _x} count (group player));

The wiki says

Syntax: condition count array

Parameters: condition: (optional) Code that must return true to be counted.

The variable _x will contain the currently tested element.

array: Array

Return Value: Number

so you have a condition -- {alive _x}

when each element is tested, if it tests as true (alive) count is increased by 1? And count continues to the end of the bounds of the array, every time? Thus the output is the count of elements within the "group" array that are "alive". Correct? Is there an exit from the count loop at all?

Forgive me, I don't have an IDE for this language, and don't know how to run scripts and display outputs in a manner that makes testing easy. Normally I would just put in a console output or msgbox and run the script to see what happens. There must be a way to do this but I haven't gotten there yet.

Anyway, if I look at the example from the code optimisation page

_someoneIsNear = {_x distance [0,0,0] < 1000} count allUnits > 0; 

is it saying this -

condition -- if distance of array element (referenced by _x) is less than 1000, value (the output or return) of count is incremented by 1

after count steps through all elements of array, count will equal the number of conditions that were true

Is that what is going on here? I think it is.

What does the > 0 do? Is that saying to count "allUnits > 0"? I think so.

Documentation is not what I am used to at all with this script language lol.

Thanks for taking the time to explain this so far!

Share this post


Link to post
Share on other sites

count exits when it has finished counting the array.

_someoneIsNear = {_x distance [0,0,0] < 1000} count allUnits > 0;  

_someoneIsNear will be a boolean, if you remove > 0 it will be an integer.

Only elements that fulfill the condition will be "counted"

Share this post


Link to post
Share on other sites

Sounds like count has no way to exit once it starts. No biggie, just wondering.

Only elements counted are the ones that meet the condition. Got it.

I am super curious now as to why the var would hold a boolean if you use the > 0 . The wiki says the return value is a number. Why is this then?

Thanks for the input btw.

Share this post


Link to post
Share on other sites

Because you're evaluating

Parenthesis might help you understand?

_someoneIsNear = ({(_x distance [0,0,0]) < 1000} count allUnits) > 0;

1. (_x distance [0,0,0]) returns an integer. Condition is (integer < 1000)

2. count allUnits that fulfill the condition (returns integer)

3. Check if that integer is larger than zero (returns boolean).

4. Assign _someoneIsNear to the boolean value.

Share this post


Link to post
Share on other sites

This line does two things which can be confusing. One is a count, two is comparing the result of it to 0 and assigning this result to the var.

What I wrote is a lot easier to digest I guess.

About "IDE": just use hint str(); or player sidechat str (); to show stuff.

You can make a test.sqf, edit it (eg. Notepad + has Arma syntax highlighting addon) and player addAction["test","test.sqf"]; for a quick run. You don't have to restart mission, just save the file. This is my test environment: simple and works.

Edited by zapat

Share this post


Link to post
Share on other sites

Just so I get this straight, and because it would seem to be a useful tool, when evaluating in this manner

variable = (condition) > 0

is akin to stating in more basic like syntax

if (condition) > 0 then  
 variable = 1 (or true) 
else 
 variable = 0 (false)
endif

Thats handy to know if thats the case.

Thank you gents for passing it on!

---------- Post added at 22:49 ---------- Previous post was at 22:39 ----------

This line does two things which can be confusing. One is a count, two is comparing the result of it to 0 and assigning this result to the var.

What I wrote is a lot easier to digest I guess.

About "IDE": just use hint str(); or player sidechat str (); to show stuff.

You can make a test.sqf, edit it (eg. Notepad + has Arma syntax highlighting addon) and player addAction["test","test.sqf"]; for a quick run. You don't have to restart mission, just save the file. This is my test environment: simple and works.

Okay, that should work.

AddAction is creating a menu item that essentially does an execVM on the script? So rather than making a trigger with onact being the execVM of the script, its just a shortcut?

lol, I am asking because I am also trying to understand how the nature of scheduled vs non-scheduled threads work, now call/spawn/exec work and how to best create scripts that behave themselves. Yep, I've played a lot of missions I downloaded and seen some that bog things down, and don't want to make that mistake, so the learning curve is quite steep ;)

Thanks for the infos.

Share this post


Link to post
Share on other sites

Hey, i am having trouble with an array, and extracting information from it. my array is this, soorryy it is quite long: 

Spoiler

loadoutarray = [
        [
        ["TRG-21 AR","arifle_TRG21_F"],["TRG-21 with GL","arifle_TRG21_GL_F"],["Mk20 AR","arifle_Mk20_F"],["Mk20 AR with GL","arifle_Mk20_GL_F"],["CAR-95 AR","arifle_CTAR_blk_F"],["CAR-95 AR with GL","arifle_CTAR_GL_blk_F"],["Katiba AR","arifle_Katiba_F"],["Katiba AR with GL","arifle_Katiba_GL_F"],["Type 115 AR","arifle_ARX_blk_F"],["Sting 9mm","SMG_02_F"],["PDW2000 ","hgun_PDW2000_F"],["Vermin SMG","SMG_01_F"],["Protector 9mm","SMG_05_F"],["SDAR Under-water Gun","arifle_SDAR_F"]
        ],
        [
        ["M1911","hgun_ACPC2_F"],["M1911 Suppressed","hgun_ACPC2_snds_F"],["P07 9mm","hgun_P07_F"],["P07 9mm Suppressed","hgun_P07_snds_F"],["PM 9 mm","hgun_Pistol_01_F"],["Rook-40","hgun_Rook40_F"],["Rook-40 Suppressed","hgun_Rook40_snds_F"],["Zubra .45","hgun_Pistol_heavy_02_F"],["Zubra .45 Red-Dot","hgun_Pistol_heavy_02_Yorris_F"],["Race Stater Pistol","hgun_Pistol_Signal_F"]
        ],
        [
        ["Medkit","medkit"],["Defibrilators","defibs"],["Smoke GL","smoke"]
        
        ],
        [
        ["Squad Sprint","sprint"],["Squad Ammo","ammo"],["Squad Explosives","explosives"],["Squad Grenades","grenades"]
        
        ]
    ]; 

And when i try to get a specific weapon class name from the first element of the array using this:

Spoiler

_primary =((loadoutarray select 0) select _primSel) select 2;

_primary is nil. i have no idea why, and i need some help. Maybe a second pair of eyes can help.

Share this post


Link to post
Share on other sites
4 minutes ago, Moldisocks said:
  Hide contents

_primary =((loadoutarray select 0) select _primSel) select 2;

_primary is nil. i have no idea why, and i need some help. Maybe a second pair of eyes can help.


You have (assuming _primSel is defined):

BLABLA select 2

Instead of:

BLABLA select 1

 

Share this post


Link to post
Share on other sites
32 minutes ago, Moldisocks said:

Maybe a second pair of eyes can help


Not unless you tell what is that you want to extract and what _primsel is supposed to be

Share this post


Link to post
Share on other sites

OK so _primSel is a variable defined by a listbox selection, it will return the index of the listbox entry selected. 

_primSel = lbCurSel 1500;

i have checked to make sure that _primSel is outputting the correct index using

systemChat str([_primSel,_secSel,_gadgSel,_perkSel]);

the array returned (depending on listbox selection is  something like this)   

[3,2,1,3]

so i know that _primSel is correct. Even when i don't use _primSel and i manual put in a number like this

systemChat str(((loadoutarray select 0) select 2) select 2);

It returns nothing.

Share this post


Link to post
Share on other sites
6 hours ago, HallyG said:

instead of:


BLABLA select 1

HOLY balls, how did i not see this, sorry was soooo tired last night when i did this haahaha, sorry for wasting everyone's time.

 

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now

×