25.12.13

My coding project, part VII

After a long break

My pygame project has advanced more than you could guess by the amount of posts about it. Mostly I've been fooling around with the background stuff, not much of what I've done will be directly visible to the user. Then again, if you look at the previous post, quite a bit has changed.

The last time we got to a part where the game world and its sectors were created and a map based on that was shown to the user. At this point there's absolutely nothing to play so I refuse to call it a "player". The map could be opened and closed and the game could be (un)paused. Basic stuff but nothing spectacular.

Next steps

In the first iteration of my project the game's view was fixed and the ship flew around freely. The first thing I had to do was to attach the viewport to the ship. So the ship would always be in the center and the viewport would scroll around the sector, following it. Because the sector would always be (much) bigger than the viewport, there was no sense in rendering objects that weren't inside the viewport's area. Therefore the sector would need a data structure for its gameobjects that would give all the necessary information to achieve this.

QuadTree

The idea of a QuadTree is that whenever a single cell's capacity is used up, it subdivides into four subcells where the objects will be redistributed. And so on and so on until the maximum depth of the tree is reached. No explanation I give can be better than the existing ones so you can read more from wikipedia, for example.
The necessary explanation is that I implemented my own version (or a part of it) of a QuadTree. At this point, when its mere existence is enough, all the sector's contents is inserted into the qtree. The aforementioned need of finding all the gameobjects inside the viewport was the first real use case. Because the sectors are squares, all my gameobjects are basically squares and all the quadtree cells are squares, everything can be solved with pygame's colliderect methods.

def get_contained_objects(self, rectangle):
  contained_objects = []
  if self.gameobjects:
    for gameobject in self.gameobjects:
      if rectangle.colliderect(gameobject.get_rect()):
        contained_objects.append(gameobject)
      if self.top_left:
        contained_objects.extend(self.top_left.get_contained_objects(rectangle))
        contained_objects.extend(self.top_right.get_contained_objects(rectangle))
        contained_objects.extend(self.bottom_right.get_contained_objects(rectangle))
        contained_objects.extend(self.bottom_left.get_contained_objects(rectangle))
  return contained_objects

What's most important in the code above is the rectangle parameter, which is the surface area of the viewport. That viewport is calculated around the centerpoint of player's ship. While working on that also the offset of the ship from the sector's 0,0 point is calculated. That offset is needed to render all the other gameobjects related to the ship.

Maybe (most likely, even) I explained it a bit funnily, but what can I do. Solving this small set of problems took a few evenings and sessions. I was pretty proud when I finally got it working properly. My biggest problem had been that I thought of it way too complicatedly - yet again.



Return of the GameObjects

Of course I needed something to be rendered on the screen, so that I could check the basic functionality of my QuadTree. In  the beginning I had those three subspace pirate ships I mentioned a related post or three ago. In addition to those I wanted to return the Asteroids back to the screen as well, but better than the last time. While I was on it, I'd test the insert and division methods of the tree with some randomly generated content.

My old asteroid code was almost directly transferrable. Mostly I added some more randomness to the init. Based on a 2d6 toss, a result between 9-12 spawns an ice asteroid, otherwise a rock asteroid. Anohter 2d6 decides the size with the old familiar small / medium / large / enormous options. The material affects both the color, the randomized mass and the rotation speed. Those asteroids that consist of rock are both heavier and slower than the icy ones.



19.12.13

Redoing the camo pattern

Yesterday evening I brushed a new camo pattern on the Turkina. I have to say that the result is still suboptimal but better than the previous attempt. Mostly that's because I had to beware of the preexisting detailing and such. Had I started all new, it'd been (hopefully) much better.




I think I'll apply a brown wash on this one, just like I did with the previous four OmniMechs. Unless I run out of paint. No matter what I'll report about that next year earliest, because I'll be on a vacation without pieces, paints and all those things.

11.12.13

Ongoing tiny fixage

December and all the other random things, also known as other projects, have eaten most of the resources from the 'Mech fixing. I've also had little inspiration for this for some reason, so other projects have actually had the chance to steal my time from this stuff. Mostly I've been educating myself about Alex Denton's adventures or had the PyCharm running, but more about that in a couple of weeks.

A guinea pig

The Assault 'Mech of the Jade Falcons - Turkina - that might end up being the Cluster Commander's ride, needed some repainting. The problem with this one and the others painted in the same batch was that the Dark Green I used (on top of black, no less!) was way too dark. Something needed to go over that and I chose Sick Green (Game Color 72029) from my storage and started brushing around.


Turkina before


Turkina now


I didn't even remember (or realize) how awful my paintjob had been. Almost the whole can was repainted without a rat's behind given about the pre-existing excuse of a camo pattern. As my next task I'll redo the pattern with semidark gray and fix the jade highlights.
Why didn't I repaint them as well while I was at it? Because I really liked the Galaxy insignia on both sides of the torso, destroying them would've been a huge shame.

Based on my experiences with this mini I'll put the rest of them in the grinder the same way. As long as I get this one done out of the way first.




2.12.13

Quick fixes III/13

Going through all the old minis

I was  bragging earlier that I'd go through all the OmniMechs I had assembled and painted years ago and redo their cockpits. Sometimes I'm a man of my word, so here's a quick report:

The beginnings of the fifth Trinary

Numerically my smallest and therefore easiest to fix was the set of four Points of my Aerospace Fighters. It really didn't take long as the cockpits are tiny and there were only four of the fighters to be fixed. In the more or less distant future I'm going to need to work on more of these, but when do I have the time for that? Not soon, I guess.



Two-legged monsters

While I was painting the cockpits I also separated the broken minis for fixing. I had also once accidentally bought an old sculpt of a Summoner that was sold as a D variant, and that was a horrible piece. That one I didn't bother touching at all as I'm going to reuse it as random ruined pieces on the bases of other, proper miniatures.


This jungle of 'Mechs isn't too clear so I'll show the pieces in a few separate rounds. First you'll find a Nova prime, Cougar prime, Cougar C, Ice Ferret and an Cauldron-Born prime. The C-Cougar had lost its right arm at some point, so it marched on towards the Mech Bay and restoration.


Next up: heavier units. First a Mad Dog, Hellbringer, Summoner as primes and a Summoner B to round them up. Each was in prime condition and without anything to complain about. Unless you want to complain about the painting decisions I'd done all those years ago, that is.



In the Assault class I had an Executioner, Gargoyle, Dire Wolf, Turkina and Warhawk, each in their prime configuration and then my absolute favourite: the totally, absolutely sick C-variant of the Warhawk (2x LPLas, 2x ERPPC, flamer, TC). Funnily enough the first four were those I had intended to repaint because I had painted them with too dark a green. I just didn't have the time to repaint them at this point, so that had to wait for a while still.


The first Timber Wolf of my Cluster (I've got two, because I like them but no more than that because they're not supposedly typical for Falcons) is naturally a prime, like so many others:



Novas

My two Novas were armed with somewhat lighter equipment than the rest of the Cluster, with the idea "run quickly to the grinder and drop the Elementals". I admit that it can fight against the very idea of a Talon Cluster's description so I'm prepared to set them up later with Heavy/Assault class 'Mechs. The point was, that personally I found the fast Omnis much more likely to be found in a Nova.

So here they are, first three Stormcrows. The ones at the edges are primes and the one in the middle's a random custom.



The next set had three Kit Fox primes and two Fire Moth primes. I can't even rememeber if at the time I ordered these there were any customizing options avaiable. Or if customizing had been even sensibly doable.

The Nova and Ice Ferret that you saw in an earlier pic were assigned to these Novas in addition to these eight.

Some damaged ones

Critical Hits had been delt out more than just once. The reason to that was of course in my own assembly methods, because the custom joints were done before my Dremel period and generally however. The first sad example is my early Hellbringer A, that got its right arm AC made from a topz pipe. This one had taken two criticals in its both Lower Arm Actuators. With some pinning they'll stay put in the future.



The second Timber Wolf of my Cluster is an A variant and it had lost half of its left arm. Just like the Hellbringer above this one had taken a critical hit in its LAA.


Luckily only three Points had lost limbs. Oh, and that one pitiful excuse of a Summoner that had gone in two pieces from its hip. But we don't talk about that because it's going to be replaced completely.
The fault in these breakings is only mine and that's why I'm going to fix them to the best of my abilities. Well, I'd do that anyway, even if it wasn't my fault.