Shooting out bullets
Monkey Forums/Monkey Beginners/Shooting out bullets
| ||
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? |
| ||
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. |
| ||
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. |
| ||
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 |
| ||
Why not using a linked list with your bullet class? Probably trying to avoid the need to create tons of new node objects. |
| ||
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 |
| ||
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? |
| ||
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). |
| ||
Why is that better than EachIn? Also, if the player has a set amount of bullets would a pool be best? |
| ||
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. |
| ||
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 |
| ||
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. |
| ||
I do not agree with Goodlooking 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. |
| ||
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. |
| ||
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 |
| ||
@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... |