Type with arrays

BlitzMax Forums/BlitzMax Beginners Area/Type with arrays

Takis76(Posted 2013) [#1]
Hello,
I have one type and I would like it to make it as array.

Type My_doors
	
	Field x:Byte 'position X on the map
	Field y:Byte 'position Y on the map

	Field state:Byte '1 opening 2 closing 3 opened 4 closed 5 locked 6 jammed
	Field have_button:Byte 'have a button to open or close it
	Field time_delay:Int 'animation speed
	Field frame:Byte 'sprite animation frame
	Field locked_with_item:String 'the item or key to unlock the door
	Field orientation:Byte 'horizontal or vertical
	
EndType
Global Doors[100] = New My_doors

The example above is a type about creating my doors type.
Is it possible to have the Doors type as an array for example 100 doors.
I tried the example above and it doesn't work.

Global Doors[100] = New My_doors <-The error is here
The example above

Thank you :)


Who was John Galt?(Posted 2013) [#2]
You're trying to assign a single door to the whole array. A door isn't 'an array of doors'.

Global Doors:My_doors[100]
Doors[0]=new My_doors
Should do it. However better to call the type 'My_door' because it represents a single door rather than an array of them.

A nice trick you will sometimes see is something like this to automatically add new instances to a list. Add this code (including the global) inside your type definition.

Globals Doors_List:TList=new TList

Method New()
    Doors_List.AddLast(self)
end method
This creates a global list within the type (i.e. scope limited to the type). The New() function if it has been declared for a type is called automatically by Max immediately after a new instance has been created by the 'New' function, hence it's a useful place to put certain runtime initialistation code.

Of course, you could adapt this to add the door to your array. I just find lists nicer to work with in most cases.

<All code untested>


Takis76(Posted 2013) [#3]
Your code worked Global Doors:My_doors[100] Thank you :)

Is it possible to add an array as a list?

For example I have one array with name levels:String[99, 43, 43, 5]
Does this works like this?
Instead have 4D array with 99 levels I will have 3D array with as many levels add in the list.
And is it possible to move the levels in the list up or down or delete some from list and how to access them?

Something like this:

Global all_levels:String[43, 43, 5]
Global level_list:TList
level_list.AddLast(all_levels)


I tried it and dropped EXCEPTION ACCESS VIOLATION error


Who was John Galt?(Posted 2013) [#4]
Not sure why you want to add an array to a list, but should be doable.

The EAV is because you need to create the list first with new().


Takis76(Posted 2013) [#5]
I tried something and it compiled.

Global all_levels:String[43, 43, 5]
Global all_levels_list:TList = CreateList()
'all_levels_list = CreateList()
all_levels[1, 1, 1] = "01"
all_levels_list.AddLast(all_levels)
all_levels[1, 1, 1] = "02"
all_levels_list.AddLast(all_levels)


I have all my map in array all_levels which is now 3D instead of 4D
I created one variable which is a TList
Then I created a list with this variable all_levels_list:TList = CreateList()

Then I set in the all_levels array at 1,1,1 one string "01"
Then I added this all_levels[1,1,1] in the list at position 0 of the list
Then I just changed the data of position of the array 1,1,1 the same position with different data "02"
And I added this new all_levels[1,1,1] in the list at position 1 of the list, because addlast just added the new array at the index 1 (Means the data added appended) in the list.

Now the list with name all_levels_list contains two arrays
at position 0 of the list the array all_levels[1,1,1]="01" and
at position 1 of the list the array all_levels[1,1,1]="02"
In fact both arrays are the same but there are different as I understood so far.

How do I access the position index of the list all_levels the index 0 or index 1 in the list and change one of the arrays which contains in each of the indices?

In my game I will have a level editor and I will add levels in a list of levels.
Each adventure will have levels and the user when will need to create some adventure will add levels in the adventure (Levels=Dungeons) and then will have access in each level which is an array from a list of all_levels and make changes, change the map, change the order of each level in the whole list , or add levels above or add levels below or insert levels or arrange the levels inside the list etc..

Difficult? :P


Who was John Galt?(Posted 2013) [#6]
List entries point to entries- so you end up with a list that points twice to the same array.

I don't think for this example lists are the best ideas- more useful for enemies and the like.

IF you want a list of levels, then create a New() array for each level which will be 2D and add it to the level list.


Takis76(Posted 2013) [#7]
I will use my current code with levels as one 4D array.
I would like to ask , is it possible to add a type in a list?
Something like this:


Type My_Items_on_the_floor
	
	Field x:Byte 'the position in the map X
	Field y:Byte 'the position in the map Y
	Field level:Byte 'the level the item is on
	Field position:Byte '4 item positions each square
	Field item:String 'the item
	
EndType
Global floor_item:My_Items_on_the_floor

Global floor_items_list:TList = CreateList()
floor_item.x = 1
floor_item.y = 1
floor_item.level = 1
floor_item.position=2
floor_item.item="01" 'Sword
floor_items_list.AddFirst(floor_item)
floor_item.item="02" 'Lock Picking tools
floor_items_list.AddFirst(floor_item)


But again how do I take access of this list for each item?

What this command do?
floor_items_list.ValueAtIndex(1) 'It seems set the index of the list
It suppose to have selected the second item.

DrawText "Item:" + floor_item.item, 0, 0 'It suppose to print the value of the selected index of the array.

It doesn't work :(


Takis76(Posted 2013) [#8]
I thing I found my way to have access to my array in the list.
I will convert the object in the list with cast.

According to the previous example:

I have one list with all of my levels

Global all_levels_list:TList = CreateList()

I have the array which hold my level data as a singular level

Global the_level[43, 43, 5]:string
I put some data in the array

the_level[1,1,1]="01"

I put the level in the list.

all_levels_list.AddLast(the_level)

The list contains only one level. Only one array. This array is an object.
I change the data of the_level

the_level[1,1,1]="02"

The data seems to be the same but in fact is another one singular level.
I add another one level in the list
all_levels_list.AddLast(the_level)
AddLast command adds one element at the end, appended.

If I want to gain access to each of my levels first I need the index of the list.
ValueAtIndex(0) command select the index in the list in my case there are 2 elements in the list the 0 and 1

Then I will need a temporary array to receive my converted data from the object to array format.
So in this point I cast the object and convert it to my 3D array I had.
The new temporary array is the_level_temp



the_level_temp = String[,,] (all_levels_list.ValueAtIndex(0))


Then I can print my data in the array.


DrawText "My array from list:" + the_level_temp[1, 1, 1], 540, 110


But there is a problem, if I will need to have access to a specific index , I only have access to the last element of the list even if I use ValueAtIndex(0)

I am close but I don't know how to fix it and have the correct index not the last one in the list.


Takis76(Posted 2013) [#9]
I tried the above example with just string variable and it worked and I was able to have the index of the list correctly selected.
With arrays it presents only the last object in the list.

The example with just simple string variables.

Global item:String
Global floor_items_list:TList = CreateList()

floor_items_list.AddLast("01") 'add one sword
floor_items_list.AddLast("02") 'add a lock picking tools
floor_items_list.AddLast("03") 'add healing potion

item= String (floor_items_list.ValueAtIndex(0))
DrawText "Item List:" + item, 540, 90

item= String (floor_items_list.ValueAtIndex(1))
DrawText "Item List:" + item, 540, 100

item= String (floor_items_list.ValueAtIndex(2))
DrawText "Item List:" + item, 540, 110


The code above worked.

But the code with arrays in the list , I receive only the last from the list.


And something else

How to convert an object to a type with cast?
Can types be elements of a list?

Thank you :)


Who was John Galt?(Posted 2013) [#10]
Wooo wooo wooo.... keep it simple man. Walk before you try to run.

First off, forget for a moment all the complications and many fields you envisage for your game. Let's work with the basic concepts and keep the examples as lean as possible to demonstrate the coding problem.

Type instances can be elements of a list. You already know that- you've been adding doors to a list and seen it running.

Type conversion is done with:

casted:myType=myType(object)

You don't really need it though- lists store any type and you don't have to convert.

You're still making the same mistake I explained to you earlier- you added an object to the list, changed a field in the object then added it again. Result, you get two pointers to the identical object in the list, which is not what you want. Please go back and re-read what I said earlier. Also, consider declaring meaningful constants rather than using 'magic numbers', e.g.

const ITEM_SWORD=1


Takis76(Posted 2013) [#11]

You're still making the same mistake I explained to you earlier- you added an object to the list, changed a field in the object then added it again. Result, you get two pointers to the identical object in the list, which is not what you want. Please go back and re-read what I said earlier. Also, consider declaring meaningful constants rather than using 'magic numbers', e.g.



I added the same object twice because if you add the same object you will have 2 objects in the list. I added it twice deliberately.

The object is not the same the first is

the_level[1,1,1]="01"

The second is

the_level[1,1,1]="02"

Why the ValueAtIndex(0) points to the last object.
You are saying about the same mistake, explain the mistake.
In my lists I want to put same objects or similar objects too.

Thank you for the type conversion from the object, I will try it.
(I don't know if it will work)
If the list with arrays will not work I will use my old method.

I bother you here , because the manual don't explain all of these in a way to understand them and there are not much tutorials.


Who was John Galt?(Posted 2013) [#12]
You don't have 2 objects in the list- you have one object in there twice. The list points to the objects, it does not hold copies of the object.

ValueAtIndex(0) points to the first object. The problem is that the first object and the second object are one and the same. The list is pointing to the same object twice.

Any changes you make to 'the_level' will be reflected by both elements in the list- the variable 'the_level', and both your list items are all referring to the same block of memory.

If you want multiple copies capable of holding independent data, you have to create them. You do this with another call to New(). If you only call New() once, you only have one object.

ball:Tball=new Tball
ball:Tball=new Tball 'The variable ball now references the second ball
                              'we created. We overwrote the pointer to the first one
                              'so it is lost and will be eaten by the garbage collector.
MyList.AddLast(ball) 'the second ball we created was added to the list
ball:Tball=new Tball 'This variable now points to the newly created (third)
                              'ball, but the second ball is not lost cos the list
                              'remembers where it is.



Takis76(Posted 2013) [#13]
So always if I want to add a new level in my levels_list need to use new?
I understand your concept but not yet the code.

Why so many complexities?

Global all_levels_list:TList = CreateList() the list prepared
Global the_level[43, 43, 5]:string the array which contains the map prepared

the_level[1,1,1]="01" put something in the array

all_levels_list.AddLast(the_level) and OK I just added the first

What next?

the_level= new the_level? I want to create another object with the same name

Or do I need to convert this array with name the_level as TLevel for example?

Something like this?

the_level:TLevel=new the_level maybe?

What is the "TLevel"? in your example Tball...

This is the point I am confused.


Takis76(Posted 2013) [#14]
Where do I will find in depth complete tutorials for these.
The language help sucks completely.
You need to bother a lots of people in the forums and wait for someone to answer or understand what you try to say and people they are not obliged to answer any newbie questions and in most cases people they are very kind and try to help but I am so newbie and I have used a lots of basics and I confuse the code.

I have used:
GWBASIC
QUICK BASIC
DARK BASIC
PLAY BASIC
VISUAL BASIC
BLITZ MAX NOW

And all of these must be similar.


col(Posted 2013) [#15]
double post


col(Posted 2013) [#16]
Hiya,

http://www.blitzbasic.com/Community/topics.php?forum=112

seems a pretty good place to start. Plenty of tutorials and complete working examples.

There is actually an example of how to use the debugger with using your final problem in your other post (Passing strings to a type) as an example to debug.

http://www.blitzbasic.com/Community/posts.php?topic=95478


Who was John Galt?(Posted 2013) [#17]
Takis,

I think you are over-complicating it and I don't know how to explain the concept in any more ways.

Dave has given you some links which may explain better.

If you are using a 3D array, no need to add it to a list. A single 3D array describes all the levels, no need for a list of them.


Takis76(Posted 2013) [#18]

If you are using a 3D array, no need to add it to a list. A single 3D array describes all the levels, no need for a list of them.



In fact I am using 4D array and I will remain with my way I use my levels and I will not put them in list.

On last thing is to understand how to add a type in a list.

I didn't understand the example of John Galt above.


col(Posted 2013) [#19]
Multiple levels can get confusing if you're using large arrays, and it seems like your trying to store too much information into one array, I don't know your game so I may be wrong.

You don't have to use Lists if you don't want to. It all depends on your game and how things/objects within your game interact.

I made a simple puzzle game which you used two 'craft' of different sizes to move blocks of different sizes through a maze using this design pattern. I'm not saying this is the best approach to use, it's just that the type of game, the way the objects interact with each other and also the ease of reading the code at a later date were deciding factors for me to use this approach. In fact if I recall correctly I did try to do it with Lists but it got confusing as I needed to know which game items were directly next to each other and/or within each other so I decided to use arrays, Your game will undoubtedly be different and may in fact benefit from Lists - it's a source code design that only you can make as you know the game. Anyway here is an outline of my approach in my game :-

Type GameLevelManager
	Field CurrentLevel:Int 			' Index in to the array of the AllGameLevels
	Field AllGameLevels:GameLevel[]		' Array of game levels
[...]
EndType

Type GameLevel
	Field Screen:GameScreen
	Field GameBlock:Block[]			' The block data thats changed during gameplay
	Field StoredBlock:Block[]		' The original block data that all GameBlock(s) are restored at every new game
	Field NoOfBlocks:Int
[...]
EndType

Type GameScreen
	Field Map[32,24]			' 2D array of solid background collision data
	Field Images:AnimatedImage[32,24]	' 2D array of graphic tiles
[...]
EndType

Type Block
	Field Image:AnimatedImage
	Field Collision:[,]			' Initial unknown size of 2D array collision data for a  block - can be made up of different shape - imagine tetris shapes
	Field Width,Height			' Used to know the width and height of the collision
	Field MapPosX,MapPosY			' Position of the block inside the Screen 2D array
	Field ScrPosX,ScrPosY			' Screen pixel position of the block
[...]
EndType


Using this structure allows me to use the GameLevelManager to very easily display any screen by changing the CurrentLevel variable within the code. The GameLevel type itself is then responsible for drawing itself and any game objects within that level:

Each GameLevel contains :-

1) Screen:GameScreen : contains background solid collision data ( never moves within the game ) and an array of images ( non collision ) to display at the corresponding 2D tile position ( later converted to pixel screen coords ).
2) GameBlock:Block[] : is a 1D array of Block(s). During loading and initialising I use GameBlock = New Block[NumOfBlocks]. Then loop through each item in the array and use GameBlock[i] = New Block, where 'i' will be the variable of a For..Next loop counting from 0 to up NumOfBlocks. On any screen there can a different number of blocks - for eg. some screens have 10 blocks, some have 5.
3) StoredBlock:Block[] : is a 1D array of the Block(s). These blocks contain the original initial state of each GameBlock ( map position for eg ). This array is the exact same size as the GameBlock array. This data is copied into the GameBlock array every time a NEW game is started.

Each GameBlock contains :-

1) Image:AnimatedImage : AnimatedImage is my own Type that I made for using animated images that will automatically update and animate themselves with a single call to an update method. You could use a simple static image. ( Max2D TImage )
2) Collision[,] : a 2D array ( unknown at compile time time ) that contains the collision data. Image the shape of a Tetris block, some parts are solid, some parts are not. This allows for different shapes - even hollow shapes. During loading and initialisation - If I want a block that is 5 units wide and 3 units high then I use Collision = New Int[5,3]. Later I access the collision array with something like Data = Collision[2,1] for eg.
3) Width,Height are the values relating to the Collision array. There are other ways to find the size of any array but this is cleanest way to read the source at a later date.

So you can know see how a single game level is made up of a background screen with graphics and collision data for the background, how game items can be stored for use during gameplay and also restored for each new game, and also see how each game item has its own data - all with an object oriented approach.


col(Posted 2013) [#20]
.


Who was John Galt?(Posted 2013) [#21]
On last thing is to understand how to add a type in a list.
You're either not reading what is being posted or you have a fundamental misunderstanding somewhere.

Type Talien    'This is where you declare your type
     'The declaration is the template for all objects of this type you
     'will create
     field x,y
end type

myAlien:Talien=new Talien 'here we create a new alien
                                        'based on the template

myList:TList=new TList
myList.AddLast(myAlien) 'here we add a 'type' to a list
                                     'as has been demonstrated many times
                                     'now in this thread



Takis76(Posted 2013) [#22]
In my game I use one 4 Dimension array which contains the data for all levels.

The array must be 4D because each level doesn't have only X and Y position but there are and the 4 sides of walls around each square.

I describe my array as:

Levels[number_of_levels,x_squares,y_squares,four_wall_sides]

I prefer the list because my game is complete dynamic.
For example I was asked about how to add a type in a list.
Because I will have a dynamic item system.

When you will travel in the dungeons and in levels you will able to pick up items from the floor and put the items back to the floor.

Each square can contain 4 item positions and these items are infinite.
If I will use array for my items on the floor of the dungeon, I will need to
be in the limit of the array.

I have different arrays for my other elements of my game.
For example I have one single array for the players inventory.
In my game I use most types.

For example if I want to put other objects in my dungeons as doors, stairs , alcoves, pits, traps , monsters , I use types with a limited array.

The alcoves can contain only 5 small items so I will not need any list.
The monsters, doors , traps and other kinds of decorations in the dungeon I use types with arrays but the arrays in these types are small up to 100 which means each level can contain up to 100 stairs , 100 alcoves, 100 doors, 100 monsters, 100 decorations etc...

But the items are something that can be in larger amount.



In the image you see above you see how my game looks like.

You see the dungeon and one door in front.
At the floor I will drop my items.

The items are the objects that are more than 100 and large arrays will consume more memory or if the player drop more that 100 items in one square the game must drop one message to say to player don't drop other item in this square or dynamically change the size of the array of max items will exist in this square.

Also there will be and level editor which means you will able to create your own adventures, new dungeons and adding levels dynamic with list will be perfect.

For now I have my array to hold up to 99 levels which are very much and each level have 40x40 square which are enough for one huge adventure. About my graphics I use one large image array which holds my graphics and the engine arrange the graphics and create the dungeons and decoration.

For now I don't have any problems with memory and most of data hold byte types of data.

Even if you have 256 items by 4 per square you allocate 1024 bytes memory for each square or 1.6Mbyte memory per level, but is impossible to have all squares full with 1024 items and all of these squares with 1.638.400 items.

Even with an array I can do my work and 100 items per square are very much , no one player will even able to put 400 items in one square.

In few words I don't have much data and there is enough memory. (For now) I don't have push the language to its limits yet.

But list will be better for example with the level editor if the levels are in a list you will able to manipulate the levels order or move levels up or down or insert levels above or bellow.

You can do this with arrays too, just copy the level with a temporary array erase the current position of the array and then copy the temporary array to a new position and you have move your level above or bellow.

But learning how the list work is better as a knowledge.

Also I don't know if I am able to resize the array but I don't know if it is possible to resize the multiple dimension array of a type on run time.

In case these complex list will not work , I will use the simpler lists.

Just adding a string in a simple list which describes what item added in the list what position on the map, what position on the square what level.

A string like "i01mx10my12sp1"

i01 means item 01 , lvl07 means the item is on the level 7, mx10 means map x 10 , my mean map y 12 sp means square position 1.

And I will use this simple list code.

Local list_of_items:TList = New TList
list_of_items.AddLast("i01lvl07mx10my12sp1")


But I was prefer adding a type in the list.

:)


col(Posted 2013) [#23]
Looking at your screenshots you seem to know what you're doing and have got reasonably far, so I won't try to corrupt with my thoughts of level storage design anymore :D


But list will be better for example with the level editor if the levels are in a list you will able to manipulate the levels order or move levels up or down or insert levels above or bellow.

You can do this with arrays too, just copy the level with a temporary array erase the current position of the array and then copy the temporary array to a new position and you have move your level above or bellow.

But learning how the list work is better as a knowledge.



You will need to understand how the TList is put together. It uses a TLink type. TLinks have a 'previous' TLink and a next 'TLink' and its actaully the TLink that stores your data, not the TList. The TList just stores multiple TLinks.

So if you want to move an item before another item, you will need the TLink(s) associated with each item ( ListFindLink will return the TLink ) then use the RemoveLink function to remove it and use the TList method .InsertBeforeLink ( or .InsertAfterLink to insert after ) to insert the TLinks where you want them. You can then loop through the list and see that the items have indeed moved position.


Takis76(Posted 2013) [#24]

Looking at your screenshots you seem to know what you're doing and have got reasonably far, so I won't try to corrupt with my thoughts of level storage design anymore :D



You are not corrupting anything if you just help me to understand how things work then you will be one of the guys who play my game when I will finished quicker.

If I will understand how these lists work not only with simple lists, but lists with arrays , lists with types , lists with types, with multiple dimensional arrays, these casts and other things in the future , you will help me to learn the language quicker and create very nice games. :)
No one corrupts anything and I thanks to all these nice and very kind people who help me to finish my game.


col(Posted 2013) [#25]
Ok, no worries, one step at a time

A simple list with swapping items, note that you need to the actual objects that you want to manipulate. In this simple example the 'objects' are strings.

Global List:TList = New TList
List.AddLast("Level1")
List.AddLast("Level2")
List.AddLast("Level3")

' Displaying the contents of the list is easy as the contents are strings.
For Local i$ = EachIn List
	Print i
Next
Print

' Lets swap Level3 and Level2
Local L3:TLink = List.FindLink("Level3")
List.Remove("Level2")
List.InsertAfterLink "Level2",L3	' Insert an instance of Object "Level2" after TLink L3 in the List

' Display the list
For i$ = EachIn List
	Print i
Next



Takis76(Posted 2013) [#26]
Why using i$ instead of i? It suppose to be a number.

Could you show me an example how to add and remove one object in a list with types.

One example with type without array and one example with single or multiple dimensions array

For example I have one type which holds my items.

Type My_items

   field x.byte
   field y:byte
   field item:string

Endtype
Global items:My_items = new My_items

Global Items_List:TList = new TList
Items_List.AddLast(items)


Then how to make a new object to able to add more item types elements in the list and don't see only the last one?

Using Items_List.ValueAtIndex(0) command.
And what kind of cast do I need to convert this object element in the list back to the type format to able to get access to it with the normal "." DOT

items.item="01"

And the one with multiple dimension array like:

Type My_items

   field x.byte
   field y:byte
   field item:string

Endtype
Global items:My_items[41, 5]
For lvl = 1 To 40
	For All_Positions = 1 To 4
		items[lvl, All_Positions ] = New My_items
	Next
Next


I keep your example for future reference.
Thank you :D


col(Posted 2013) [#27]
A small example for using a list would be something like this...

Strict

Type My_item

   Field _x:Byte
   Field _y:Byte
   Field _item:String

	Method Create:My_item(x:Byte,y:Byte,item$)
		_x = x
		_y = y
		_item = item
		
		Return Self
	EndMethod
	
	Method Debug()
		Print "x: " + _x +" y: " + _y + " item: " + _item
	EndMethod
EndType


' Initialise the item list
Global Items_List:TList = New TList

RestoreData ItemsData
Local ItemCount
ReadData ItemCount

For Local i = 0 Until ItemCount
	Local x,y,itemname$
	ReadData x,y,itemname$
	
	Local NewItem:My_item = New My_item.Create(x,y,itemname)
	Items_List.AddLast(NewItem)
Next

' Display the items in the list
Print "~nDisplay the List items using the 'EachIn' operator..."
For Local Item:My_item = EachIn Items_list
	Item.Debug
Next

' Or another way to step through the list could be using TLink(s)...
Print "~nDisplay the List manually using TLink(s) and cast the value of a TLink to a My_Item..."
Local ItemLink:TLink = Items_List.FirstLink()
While ItemLink <> Null
	Local Item:My_item = My_item( ItemLink.Value() ) ' NOTE the cast!! ItemLink.Value() will return Object type so cast from Object to My_item
	Item.Debug
	ItemLink = ItemLink.NextLink()
Wend

' another way using ValueAtIndex
Print "~nDisplay the list using ValueAtIndex..."
For Local i = 0 Until 3
	Local Item:My_item = My_Item( Items_List.ValueAtIndex(i) ) ' Notice the cast here again
	WriteStdout "List Index " + i + ": "
	Item.Debug
Next


#ItemsData
DefData 3 ' No of items in the data
DefData 1,1,"01"
DefData 6,2,"02"
DefData 3,8,"03"


There a couple of things to note here in the example.

First, there is a 'helper' method within the item type to create an fill each type with data in one easy command. When you want a new instance of an item you can now use Local Item:My_item = New My_item.Create(1,1,"item information"). Makes things really simple and you have reasonably tidy code to read on later.

And second, there is also the cast from 'Object' to 'My_item' that I've commented in the code. You can attempt to cast from any type to any other type ( Object is also a Type, its the default base type of ALL types ) and the code will run but it doesn't mean the cast will be successful - you should really ALWAYS check if the item that you cast to is valid, so in the examples above you would double check the cast using...

Local Item:My_item = My_Item( List.ValueAtIndex(0) )
If Item = Null ' the cast WASNT successful.
[...]
Endif

Of course cast checking only applies if you are putting different Type(s) within the same TList.

Before going any further, may I ask why you choose to use '01' '02' '03' for the item,item ??


Takis76(Posted 2013) [#28]
Your code I very interesting , I am at work now and I will see it after few hours.
My types in the list are the same so I will not need to check if the cast is correct.
But your example is nice to have and this option too.
I understand some of your code and I see and new things like DefData which I don't know what is this.
Read and restore data which I don't know what are these.

It seems something like the old data command of quickbasic and when we use the read command to read these data.

Something like enumerations to add the items in the list.

The confusing code is this bellow


RestoreData ItemsData
Local ItemCount
ReadData ItemCount

For Local i = 0 Until ItemCount
	Local x,y,itemname$
	ReadData x,y,itemname$
	
	Local NewItem:My_item = New My_item.Create(x,y,itemname)
	Items_List.AddLast(NewItem)
Next


For me it will be easier to use a code like.
Local NewItem:My_item = New My_item.Create(1,1,"01")

The readData x,y,itemname$ just read the defData after the #ItemsData

I have not undestood this RestoreData and ReadData much but using the variables directly is the same.

Your code seems to be perfect for my game, I will adopt it in my code and when I will finish some basic item system I will send you a demo.
Now I am working with the multiple arrays in types, to add my decorations in my dungeons, doors, alcoves,stairs, pits.

When I will finish the door decoration of the dungeon I will post a demo to see what I have done so far.


col(Posted 2013) [#29]

Read and restore data which I don't know what are these.

It seems something like the old data command of quickbasic and when we use the read command to read these data.



Yes, they are old classic Basic commands - I only used them here for the purpose of producing a working example. Normally I would load the data from a file in a similar way. If you were to do the same then you could make a completely separate editor application which will save the level data from the editor, then in the main game you would load that data.


The readData x,y,itemname$ just read the defData after the #ItemsData



Yes, thats correct too.

ReadData can be confusing at first as it has its own internal hidden pointer. We don't have access to it. The only thing we can do is point the internal pointer to a label ( the #ItemData ) using the Restore command. Then ReadData will read the first piece of data from the next DefData statement and update its own internal pointer to point to the next data within the same or any following DefData statements. Does that make sense ?

ReadData x,y,itemname$

is exactly the same as

ReadData x
ReadData y
ReadData itemname$



The confusing code is this bellow


Looking at the data :-
#ItemsData
DefData 3 ' No of items in the data
DefData 1,1,"01"
DefData 6,2,"02"
DefData 3,8,"03"


and the code
RestoreData ItemsData
Local ItemCount
ReadData ItemCount

For Local i = 0 Until ItemCount
	Local x,y,itemname$
	ReadData x,y,itemname$
	
	Local NewItem:My_item = New My_item.Create(x,y,itemname)
	Items_List.AddLast(NewItem)
Next


RestoreData ItemsData and #ItemsData are related. Its sets the internal ReadData pointer to point to any DefData statements after the #ItemsData label.

Local ItemCount
ReadData ItemCount


will read the integer '3' from the first DefData statement into the ItemCount variable, and adjust its internal ReadData pointer to point to the next piece of data in either the same DefData statement or any next DefData statements.


For Local i = 0 until ItemCount [...]Next

is the same as For Local i = 0 Until 3[...]Next ( which is also exactly the same as For i = 0 To ItemCount - 1 )


Local x,y,itemname$
ReadData x,y,itemname$


will read 2 integers and 1 string value from the next DefData statement, ie. DefData 1,1,"01" and place the values into the variables x,y,itemname$


Local NewItem:My_item = New My_Item.Create(x,y,itemname)

does a couple of things in one line-
it will create a New My_item object BUT using the Create method of the My_item Type to do so ( if you have a New method in the Type then that WILL still be called first, just like a standard constructor method ).
However, for this to work correctly you will notice in the Create method that the return type is a 'My_item' Method Create:My_Item([...]) and also notice at the end of the method there is a Return Self. This will return itself as a return value - ie return a My_item Type.
This is then stored in the local variable Local NewItem:My_item. We then store that new object in the list using the Items_List.AddLast(NewItem)
To better understand how it is working I advise you to build in Debug mode and put a DebugStop before the For.Next loop statement then use the debugger to step into the methods one statement at a time.

The loop continues using the For...Next loop reading and storing 3 new My_Item objects into the list. Once the loop exits the only reference you have for those items are in the Items_List itself.


For me it will be easier to use a code like.
Local NewItem:My_item = New My_item.Create(1,1,"01")



What happens when/if you want to write an editor - you mentioned that you will do. Also what if you want hundreds of items? Then you'll have hundreds of those lines, which is ok, but could get difficult to read and very repetitive to type out. Using data, either as DefData or loading data from a file, is the usual route to take and a better source code design.


Takis76(Posted 2013) [#30]
You are a perfect teacher and thank you very very much for your huge patience and effort you put and you stayed to teach me how nice things work.
You are very kind.
Now I will finish my doors decoration for my game using for now types with 2D arrays , I will post one quick version and then I will start making some experiment with this new nice code to create my inventory and item system.

One last thing if you would like just show me how to add one 3D array in a list.

And how to cast this object in the list back to 3D array again.

And the most of core things in the engine will be ready.

As we spoke about level editor I have started something.

Very early adventure editor.


Is in the early stage and I use ifsogui for my buttons and gadgets.

- I have made and research in forums and I found how to save my adventure and encrypt it to avoid cheaters.
- I have found how to open files and save and load data.
- I use koriolis zip module to load my graphics fonts and other data from compressed files.
- I found in the forums how to have a splash screen when my game loads in the beginning
- I found how to make light effects in my game from the forums again.

If I will find and how to store my data back to zip files with password, I will be able to create and plugins and add ons for my game or the user will be able to generate stand alone adventures. This will be a future option. (Koriolis zip module is not capable to store files in zip)
I will find how to load video clips or some compressed video clips which don't occupies large amount as the normal avi files for my cut scenes or intros or in game progress videos. Also this divX encoder is not usable.

Another one thing I will need to find is how to able to have bitmap fonts, I load truetype (ttf) fonts and I want my game being translated to many languages and there are problems with fonts or code pages or unicode and you can see the text correctly in some computers and wrong in others, so the bitmap functions will be very nice. For now I use true type fonts.

I will not bother you for this stuff yet because I have other priorities. I build the core engine of the game for now.

Again millions of thanks to all kind people here and the development goes very nice.


col(Posted 2013) [#31]

One last thing if you would like just show me how to add one 3D array in a list.

And how to cast this object in the list back to 3D array again.



Sure, no probs...

Strict

' A random 3d array filled with data
Global RandomArray[10,10,10]
For Local x = 0 Until 10
	For Local y = 0 Until 10
		For Local z = 0 Until 10
			RandomArray[x,y,z] = x * 100 + y * 10 + z
		Next
	Next
Next
 
Global List:TList = New TList
List.AddLast(RandomArray)

Local CopyOfArray:Int[,,] = Int[,,]( List.First() )

' Access array as normal
Print CopyOfArray[3,2,1]


Casting is easy, however you need to think about what you are casting to then use the parenthesis around the object that you want to cast from. In this case this want to cast to a 3d array of integers. We don't even have to know how many elements are in the array. The command List.First() returns an Object type so to cast to a 3d array of integers you use

Local CopyOfArray[,,] ' Integer array of unknown size but 3 dimensions.
CopyOfArray = Int[,,]( List.First() ) ' Cast from Object to 3 dimension array of integers.

The game looks promising. Good luck with it :)


Brucey(Posted 2013) [#32]
Another one thing I will need to find is how to able to have bitmap fonts, I load truetype (ttf) fonts and I want my game being translated to many languages and there are problems with fonts or code pages or unicode and you can see the text correctly in some computers and wrong in others, so the bitmap functions will be very nice. For now I use true type fonts.

There are lots of fonts which support the popular parts of unicode (ASCII, cyrillic, Japanese, Simplified Chinese, etc). If you store all your texts as UTF-8, you should have no problems loading them for different languages in your game.


Takis76(Posted 2013) [#33]
I made some test and I tried Greek Language and when I was load the text from a file I was seen the text with different characters and when I was typed the text from the source code directly I saw the text correctly.
Also I tried and other fonts and I had a negative effect.
The text directly from the source code was with different characters and the text which loaded from file was correctly.
Note: The text I am creating, I create it with notepad and I save it as ANSI.

If you have some text editor which saves the texts better I am open for suggestions.
I plan to write the game in English - Greek - Polish - French - German - Spanish - Italian languages.


Brucey(Posted 2013) [#34]
On Windows, I use Notepad++ for text editing. It has good unicode support.
It's not a good idea to have your unicode texts directly in the source - better to load them in from an external file. This way you know everything is correctly encoded (UTF-8, or whatever you decide to use)

BlitzMax's native Strings are stored in memory as UCS-2 (like a partly cut-down version of UTF-16).
I personally always use UTF-8 for text with BlitzMax as it is well supported across multiple platforms.


Takis76(Posted 2013) [#35]
Thank you , I will try to find Notepad++
My door functions are almost ready.


Takis76(Posted 2013) [#36]
I am very happy to announce that I have finish the door functions and I have uploaded one small demo to see what I have created so far. I used the code you gave me above.

You are moving with arrow keys or numeric pad keys. You are turn left and right with 7 and 9.
With Numeric pad MINUS and PLUS , change the light level of the level.
Also you can move with navigation arrows on interface.

You can change the order of items in inventory.
You can't put items of player hands yet.
You can't put items on the floor yet. (When I write the code which gave me I will post next demo).

Download the small demo from cloud box link bellow:

https://app.box.com/s/ioksz3rn2q5ukkh47cop


Calibrator(Posted 2013) [#37]
What's there is good, IMHO!

Only two small thoughts:

I think the doors should really open a bit quicker, perhaps x2 for regular doors. Not every door in a dungeon is a "special event"...

The compass rose turns waaaay too slowly. I can move very quickly through the corridors, turn etc. but I wait 3-4 seconds for the compass to show the right direction? In this case I wouldn't use it at all.


Takis76(Posted 2013) [#38]
Did you like it?
About doors, I will do them little faster if you want.
About compass, in real world one compass doesn't turns very quickly even if you change direction fast. But I will make it little faster but not very fast.
In my computer I have more than 400 frames per second and I see a fast enough speed here.

Later on I will try to have a fix frames per second. When my game become larger and I will have smaller frames per second. For now I don't have any problem with frames per second and I see my game in nice speed.

For animations I use timers so the speed must be the same in any computer, but this depends how much frames per second you have and how fast video card you have too.

But I believe the graphics are 2D and you don't need any very fast computer.

-------
In the next version I will use fixed refresh rate at 60 FPS so the speed will be the same in most computers.


Calibrator(Posted 2013) [#39]
> Did you like it?

Yes, it's very faithful to the old Eye of the Beholder or Dungeon Master type games.
Did you draw the graphics yourself or did you have help?

> For animations I use timers so the speed must be the same in any computer, but this depends how much frames per second you have and how fast video card you have too.

OK, now I understand - my graphics are always locked to the monitor frame rate which is 60 fp/s.

When your game will get slower (with A.I., more effects etc.) you will notice that the compass gets slower, too.

I don't see a difference between what you call "animations" and the animation of the compass - you should also make it speed independent.


Takis76(Posted 2013) [#40]
In the next version I will lock in 60 frames per second and the animations will be much faster. I tested the game here with 60 frames per second and was veryyyyyy slow and I fixed it.



I don't see a difference between what you call "animations" and the animation of the compass - you should also make it speed independent.



The doors opening and closing are animations , the compass needle turning is an animation, the gargoyle wings in the magic panel is an animation , the torch flame is an animation.

Each animation is independent.

The file updated with normal animation and fixed 60 frames per second.

https://app.box.com/s/ioksz3rn2q5ukkh47cop


Calibrator(Posted 2013) [#41]
That's much better!

I have no further complaints right now... ;-)


Takis76(Posted 2013) [#42]
Perfect, I will post another version when it will be ready.