Shooting out bullets

Monkey Forums/Monkey Beginners/Shooting out bullets

Impmaster(Posted 2014) [#1]
Hey all. I have a small game where a ship shoots out bullets. Now, the way I would have done that before would be to make an array in the ship class, then make each element in that array render whenever the ship class would go through the render loop. However, I can't seem to find a flexible array that is capable of changing it's size in Monkey X, and I don't even know if that's smart programming. How would you guys do this?


Goodlookinguy(Posted 2014) [#2]
Use Stack. It'll resize when it needs to and uses an array for the backend.

Edit: I think an array list would actually be more appropriate, but Monkey doesn't come with one by default.


Impmaster(Posted 2014) [#3]
An Arraylist is what I was looking for, but as you said, there doesn't seem to be one. From what I've seen, Stack is fairly similar though. I guess I could just use that.


Danilo(Posted 2014) [#4]
An Arraylist is what I was looking for, but as you said, there doesn't seem to be one.
Why not using a linked list with your bullet class?
Class Bullet
    Field x:Int, y:Int
End

Function Main()

    Local lst := New List<Bullet>

    For Local i := 0 To 10
        lst.AddLast( New Bullet )
        lst.Last.x = i
        lst.Last.y = i*2
    Next

    For Local bullet := Eachin lst
        Print bullet.x
        Print bullet.y
        Print "-----"
    Next

End



Goodlookinguy(Posted 2014) [#5]
Why not using a linked list with your bullet class?


Probably trying to avoid the need to create tons of new node objects.


Midimaster(Posted 2014) [#6]
To create a class of bullets with a list inside is the best you can do.

Ok, the bullets came from the ship, but during their live cycle they have no longer any relation to the ship. So they should not be a array of the ships class! They are independent objects.
Class Bullet
     Global All:List<Bullet> = New List<Bullet>

     Function Fire:Void(X%,Y%)
          All.AddLast New Bullet(X,Y)
     End

     Method New:Bullet(x%,y%)
          Self.X=x
          Self.Y=y
     End

     Function CheckAll:Void()
          For Local loc:Bullet = EachIn All
               loc.CheckOne()
          Next
     End

     Function DrawAll:Void()
          For Local loc:Bullet = EachIn All
               loc.DrawOne()
          Next
     End

     Method DrawOne:Void()
           ' draw bullet here
     End

     Method CheckOne:Void()
           'check life cycle and collisions here
     End
End


The Main code needs not to care about each single bullet. The class works autonom. There are only three functions to "communicate" from the main code:

' in case of fire a bullet:
     Bullet.Fire(ship.x, ship.y)
' in OnUpdate()
     Bullet.CheckAll
' in OnRender()
     Bullet.DrawAll



Impmaster(Posted 2014) [#7]
Actually, what midimaster is proposing actually seems to be quite smart. So you're saying that the bullet class is actually a bullet holder, where it holds the data of all the bullets in the game?

BTW, what's a list? Is it like a mutable array?


Goodlookinguy(Posted 2014) [#8]
A note about Midimaster's code: You may want to avoid using the foreach type loop in the case of bullets. It may be best to a swap out this...
For Local loc:Bullet = EachIn All


For this...
Local nextNode:list.Node<Bullet> = All.FirstNode()
Local node:list.Node<Bullet>
Local bullet:Bullet

While nextNode <> Null
	node = nextNode
	nextNode = node.NextNode()
	bullet = node.Value()
	
	' node.Remove()
End


If you have to remove the bullet nodes from the list a lot.

BTW, what's a list? Is it like a mutable array?


List is a linked list. Data is stored in nodes which are linked together. The stack data structure is a mutable array basically (not really, but for a less technical sense, it's close enough).


erebel55(Posted 2014) [#9]
Why is that better than EachIn?

Also, if the player has a set amount of bullets would a pool be best?


Goodlookinguy(Posted 2014) [#10]
Why is that better than EachIn?


Aside from avoiding the need to create a new object enumerator, it allows direct access to the nodes which allows you to remove the nodes directly instead of the much heavier route of using RemoveEach.

Also, if the player has a set amount of bullets would a pool be best?


It depends. Games are never programmed just one way. Pooling a bunch of bullets could help reduce garbage collection's impact. Can't really say more than that because I haven't had to use pool.


Midimaster(Posted 2014) [#11]
I do not agree with Goodlookingguy....
The LIST is as smart as his node model, but makes understanding more easy.... and fast enough, if the number of elements is <1000

Yes the CLASS encapsulse all bullets and cares about all the things related to them. A LIST of bullets is comparable to a "staple" in real life. You can easyly do something to all bullets by iterating thru the list.

Picking a certain object anywhere in the list is only possible by scanning them all. F.e if you want to delete a bullet you walk thru the list, search for the matching bullet, find it and then kill it:

Function KillAllGone:Void()
     For Local loc:Bullet = EachIn All
          If loc.X<0 then All.Remove loc
     Next
End

With removing it from the list, the bullet is also dead.

But you can also return a list element, if you need a scope on a bullet for a longer time in main code:
 ' anywhere it main code: 
LongNeededBullet:Bullet = Bullet.Number(123)


Class Bullet
....
Function Number:Bullet(id%)
     For Local loc:Bullet = EachIn All
          If loc.Id<id  then Return loc
     Next
     ' if nothing found
     Return Nulll
End



Gerry Quinn(Posted 2014) [#12]
A list is generally the easiest solution. You can remove 'dead' objects (bullets that have expired, ships that have sunk) easily.

If minimising the creation of objects is an issue, arrays can be useful. Dead objects can be marked, and re-allocated when a new object is needed, or skipped over otherwise.

A stack is like an array but you don't need to decide the size in advance. If it fills up, it can grow.


Goodlookinguy(Posted 2014) [#13]
I do not agree with Goodlookingguy....
The LIST is as smart as his node model, but makes understanding more easy.... and fast enough, if the number of elements is <1000


...what are you talking about? My code is using List and more specifically is building on your code. Are you unfamiliar with treading through the list nodes individually instead of using the for-loop structure?

Edit: Oh, and if you consider the for-loop structure as smart as using the nodes from the list directly, then why does it take your method way longer to deal with node removal? Don't fight my points when you don't know what you're talking about.


Jesse(Posted 2014) [#14]
yes nodes are better when using a while loop than using a list with the for/loop. Not only because you are dealing directly with objects but also because the for/loop create unnecessary objects.


Danilo(Posted 2014) [#15]
It is good to know both ways, thanks.

If I understood correctly:
Class Bullet
    Field x:Int, y:Int
End

Function Main()

    Local lst := New List<Bullet>

    For Local i := 0 To 10
        lst.AddLast( New Bullet )
        lst.Last.x = i
        lst.Last.y = i*2
    Next

    '
    ' ForEach Loop
    '
    ' - creates new bullet object for each loop (make copy)
    '   instead using it ByRef
    '
    For Local bullet := Eachin lst
        Print bullet.x
        Print bullet.y
        Print "-----"
    Next
    
    Print "---------------"
    
    '
    ' Node traversal
    '
    ' - uses the object in the list directly by
    '   copying the object pointer only,
    '   instead creating a new object
    '
    Local nextNode:list.Node<Bullet> = lst.FirstNode()
    Local node:list.Node<Bullet>
    Local bullet:Bullet

    While nextNode <> Null
        node = nextNode
        nextNode = node.NextNode()
        bullet = node.Value()
        Print bullet.x
        Print bullet.y
        Print "-----"
    End

End



Midimaster(Posted 2014) [#16]
@GoodlookingGuy
Sorry, my mistake... I did not want to offent you. Maybe my bad english is the reason,why it sometimes sound harsh...
I only had the impression, that Impmaster is not very familiar with LISTs. And it may be to soon to show him NODEs...