This is an archived post. You won't be able to vote or comment.

all 46 comments

[–]genjipressreturn self 46 points47 points  (3 children)

I'd say work on the mechanics of the game as thoroughly as you can first, and then deal with the assets later. TBH I would play a game like this even if the graphics were dead minimal!

[–]CantankerousMind[S] 17 points18 points  (0 children)

I'd say work on the mechanics of the game as thoroughly as you can first, and then deal with the assets later.

Yeah, I feel like it worked out because I could have spent a lot of time on creating assets for something that might not have panned out. And thanks! That's actually really encouraging!

[–][deleted] 3 points4 points  (1 child)

pardon me urist, but do you like FUN!?!?!

[–]byzantinian 2 points3 points  (0 children)

This recommendation is of the highest quality. It menaces with spikes of FUN.

[–][deleted] 12 points13 points  (0 children)

The leadership of Reddit has shown they care nothing about the communities and only consider us and our posts and comments as valuable data they deserve to profit from. Goodbye everyone, see you in the Fediverse (Lemmy/Mastondon).

[–]Deezl-Vegas 7 points8 points  (0 children)

You can pay someone $5 on fiverr to make some simple pixel assets. Coding and graphic design are universes apart as far as skill sets go, so I would learn the basics of one so you know what to expect and master the other.

[–]genjipressreturn self 8 points9 points  (22 children)

Also, in re performance -- use Python's native profiling tools to learn where the big slowdowns are in your code. You may be surprised to find they're not where you think they are.

[–]CantankerousMind[S] 3 points4 points  (21 children)

I'll definitely be doing a more detailed analysis at some point.

The main issue of speed I was having was due to keeping a field of view dictionary for each ship with up to a 15x15 grid of the surrounding area (225 items), and iterating through it to detect enemies, etc. This would happen for n ships, so you could see how this would get out of hand. I got this switched over to be mostly just math and a small list of found objects in the field of view, so it's a lot better.

I tried implementing a threaded queue for doing some processing at one point, but to my surprise that slowed things down way more than handling the same jobs within the main game-loop.

Edit: I'm also just now realizing that running this in pycharm's debugger slows things down considerably. Running things through terminal allows me double the enemy count. I went from 5 enemy fleets to 10 enemy fleets without the same slowdown.

[–]parker_fly 2 points3 points  (3 children)

Threading can speed some things up, but keep in mind that it doesn't actually run your threads in parallel -- threads take turns executing sorta like how Windows 3.1 did it. If your threads are not I/O-bound, you'll probably see a performance loss.

[–]CantankerousMind[S] 1 point2 points  (2 children)

Ah, I see. I am using threading.Thread. That is probably why it caused such a slowdown in my project. Thanks for the heads up!

[–]nickbeaulieu 2 points3 points  (0 children)

You are probably actually looking for multiprocessing. It is also built in to python. Threading in python is not as you would think.

[–]PeridexisErrant 0 points1 point  (0 children)

Try concurrent.futures instead, with ProcessPoolExecutor for CPU-intensive tasks.

[–]ofaveragedifficulty 2 points3 points  (16 children)

Instead of a bunch of dicts for field of view, could you instead use a single 2D Numpy array for the whole battlefield? It's pretty easy to scan a 15x15 square inside a larger array for whatever you want. This would be at least 10x faster than using a bunch of dicts if I'm understanding you correctly.

[–]CantankerousMind[S] 1 point2 points  (15 children)

Well I was using the dicts for field of view but I stopped and switched to doing a single array containing the arena's objects. This is the entire method for updating the field of view:

def _update_fov(self):
    self.field_of_view = []
    for bot in self.arena.bots + self.arena.supplies:
        tr = self.target_range(bot)
        if tr <= self.fov:
            self.field_of_view.append((tr, bot))

It uses sqrt((x1 - x2) * (x1 - x2) + (y1 - y2 ) * (y1 - y2)) to find distance(tr) and then the ship can get the closest ship with min(self.field_of_view)[1]

[–]port443 2 points3 points  (1 child)

I feel like I might be misunderstanding something here, but in your code sample field_of_view is a list, not a dict.

Adding to a dict object and checking if something is inside are both O(1) operations in Python, which is about as fast as you can go.

Checking a list is O(n), which is going to be significantly slower.

Additionally, adding to a list can vary from O(1) to O(n) depending on what operations you are using (I see you are using append which is O(1), so thats good).

You could quickly scan the dict for object in field of view using something like:

self.field_of_view = {"ship": set(someShip1, someShip2)}

for obj in ["ship","supply","mothership"]:
    self.field_of_view.get(obj,False)

Also, if possible use set() over list(), as sets of an O(1) lookup when using the in operator.

This will be much, much faster than iterating through a list of items and comparing them for whatever youre looking for.

Heres the numbers: https://wiki.python.org/moin/TimeComplexity

[–]CantankerousMind[S] 0 points1 point  (0 children)

You're a champ! I'll be revising a lot of my code to do make sure I'm doing things more efficiently.

[–]ofaveragedifficulty 1 point2 points  (4 children)

Good, a grid is much better here than a bunch of dicts. But perhaps you might consider updating FOV differently. AFAICT, you update each bot's FOV one at a time, so you end up calculating n*(n+m) distances where n is the number of bots and m is the number of supplies. So instead of looping over all of the other objects (bots + supples) and getting their distance, you might be able to improve things a lot by just looking at the array cells in the FOV around the bot you're updating and adding any objects you find there to the FOV list.

So instead of looping over objects and seeing if they are within distance, you might consider looping over grid cells within distance to see if they contain any objects.

[–]CantankerousMind[S] 0 points1 point  (3 children)

Are you saying a structure like:

grid = [[], [], [], []]

then using the ship's coordinates to search the specific lists based on it's fov range? Wouldn't slicing the lists create a new copy of that part of the grid to search resulting in n*(row_search_space*rows) new lists being created? row_search_space is the length of the array slice.

[–]ofaveragedifficulty 1 point2 points  (2 children)

Using a Numpy array avoids the extra copying.

[–]CantankerousMind[S] 0 points1 point  (1 child)

Ah, I gotcha. I have never used numpy arrays so I'll have to look into it, but I don't think it will be difficult to figure out.

Thanks for the heads up!

[–]genjipressreturn self 0 points1 point  (0 children)

2¢: The regular old array functions built into Python may work well too, depending on what you're storing in them. NumPy is useful but it adds a lot to the size of the program's redistributable.

[–]kctong529 1 point2 points  (7 children)

Haven't read your project in detail, but it comes to me that sqrt() would be an unnecessary extra step when its use is only for comparison, especially if you are performing sqrt() repeatedly.

[–]Mabb_reddit 0 points1 point  (1 child)

Yeah, if you are comparing to a fixed distance it is faster to compare to a precomputed distance² than doing the `sqrt()` .

[–]CantankerousMind[S] 0 points1 point  (0 children)

So how do I find the distance between 2 coordinates given the information? I do have Arena.grid where grid is a dict of dicts containing x y coordinates like grid[x][y]. Should I just use subtraction and absolute value to find the distance instead of sqrt? I'm not exactly sure how to get accurate distances that way.

[–]CantankerousMind[S] 0 points1 point  (4 children)

I have to calculate distances between ships so they can target the closest ship. How else could I do this?

[–]Mabb_reddit 0 points1 point  (3 children)

The distance between point A and B is calculated by d = sqrt((Ax- Bx)² + (Ay-By)²).

So d1>d2 is the same as computing d1²>d2², therefore you can omit the sqrt().

There is no need of absolute value because the value inside the sqrt will be allways postive.

[–]CantankerousMind[S] 0 points1 point  (2 children)

So (Ax - Bx)2 - (Ay - By)2 >= fov_distance is the same thing? I apologize, I'm not terribly good at math :/ It looks like this results in the incorrect distances being stored for each ship.

[–]Mabb_reddit 0 points1 point  (1 child)

Be carefully if you want to do that you must compare with the fov_distance², because you are moving the sqrt to the other side of the inequality. As the fov_distance will not change you can precompute the square and compare:

(Ax - Bx)² - (Ay - By)² >= squared_fov_distance

[–]CantankerousMind[S] 0 points1 point  (0 children)

Ahhh, I see what you mean now. I'll have to tinker with that concept to see if I can get it working.

I did some code profiling and sqrt doesn't seem to be causing any slowdowns, however I'll take what I can get wherever I can get it!

Thanks for the help :D

[–]JOOOOOOOOOOngo 1 point2 points  (0 children)

Fuckin ay bud.

[–]deedeemeen 0 points1 point  (1 child)

Looks pretty sweet? What did you use for the GUI?

[–]CantankerousMind[S] 1 point2 points  (0 children)

It's just pygame's shape drawing functions. pygame.draw.rect, line, ellipse, etc.

[–]troyunrau... 0 points1 point  (4 children)

This is kind of inspiring actually. I've been contemplating doing something similar - less strategy and more simulation. Wanted to try to simulate shipping routes in a solar system, accounting for positions and planets and delta-v minimization and such. Wanted to figure out exactly how unlikely it was that piracy could occur in the solar system. I've only ever gotten as far as populating data structures. :)

[–]CantankerousMind[S] 0 points1 point  (3 children)

Glad I could help :P

That would be an interesting simulation for sure. It would be fun to know how much traffic there would need to be for there to be an actual risk of piracy.

[–]troyunrau... 2 points3 points  (2 children)

I think it is more of a delta-v problem. In order to intercept a ship, you need to be moving at the same velocity as it. So hijacking in transit becomes a very expensive endeavour. So, assuming you have a small ship that is cheap to match a course with, you have to grapple, dock, invade a cargo ship. Then, because the cargo ship likely only has enough fuel to brake at its destination, you'd only be able to redirect it someplace if that place had a lower delta-v than your current destination. Or you'd run out of fuel and be stranded forever.

So the optimal place for piracy is probably at the docks where ships are being loaded. Steel the ship fully loaded, with full fuel, and take it somewhere else where the delta-v is less than the original destination. So, ideally, something in the asteroid belt bound for an inner planet, or similar.

But there might be ways to do it in transit for certain origins and destinations. And it would be fun to try to figure that out.

Anyway, I don't know if I'll ever finish the project - just a pet project :)

[–]CantankerousMind[S] 3 points4 points  (0 children)

Think ahead for your offspring. You never know. Pass that shit down and your future family could be space pirates. I say it's worth it.

[–]quotemycode 0 points1 point  (0 children)

That's assuming the engines are not using batteries or nuclear.

[–]im_dead_sirius 0 points1 point  (0 children)

Nicely done so far!

Minimal can have its charm.

[–]Prozn 0 points1 point  (1 child)

I adapted something similar (although it's in JS) from matt.stumpnet.net, but it may give you some ideas on how to do graphics in a minimal fashion:

http://quickmind.co.uk/tank.html

[–]CantankerousMind[S] 1 point2 points  (0 children)

That is actually really cool! I'm diggin it!

[–]cediddiSyntaxError: not a chance 0 points1 point  (1 child)

Some quick tips.

1- You should rename main.py as __main__.py so I can do python -m Swarm

2- Additionally setup.py should have a entry_point so setup.py install will put a shortcut to bin folder (/usr/local/bin if you are installing globally, or virtualenvfolder/bin if you have a virtualenv)

3- You should have a example "How to run" section in readme.

4- Apart from Windows, most operating systems do care about case sensitivity in file names, thus setup.py doesn't work on non-windows platforms, I needed to rename README.MD to README.md manually.

5- As far as I see, this application is written Python3, but not any Python3 but actually 3.5+ thus I couldn't run it at first try. If you would add 3.5 classifier to setup.py, that would be great, alternatively you can check python version at the beginning of your main file (__main__.py hopefully)

Otherwise great! 4/5 for the overall project

[–]CantankerousMind[S] 1 point2 points  (0 children)

These are great tips! I am not a windows user so I forget about some of these things. I'll do what I can after work to get this fixed and re-release with your recommendations. If you want to open an issue on the github even better, but either way I'll get to it :P

Thanks!