Forum :: Mods :: More script help for Eckels...

Sign In

You must sign in to post.

More script help for Eckels... :: May 6, 2007 @ 7:06pm

Ensign eckels

Joined: Mar 4, 2007
Posts: 200

I'm trying to draw a circle around a planet.

I looked at the code that sir_gnip used to make his expanding ring,  but I don't understand it.

I also tried using the pygame.draw.circle() function that's included with pygame, with no success. I don't think i'm defining the surface properly. I'm not sure. 

What I'd really like to do, is display a thick colored line around a planet. - similar to how the glows look like for teams, but more defined, and visually detached from the planet itself - more of like a halo. 

Can you point me in the right direction on what code to look at? I'd be happy to figure it out for myself, but I dont even know where to start.

edit: I've found             screen.circle(c,p.pos,p.r+pad,2) from the hover display, that'll work. only question is - is there a way to change the color of the circle?

edit 2:
I can't figure out how to get the circle to draw... i've been trying to figure this out for about four hours now, and I really need someone to point out what i'm doing wrong. I've tried everything i can think of, and a whole bunch of stuff i read on python.org and pygame too..

here's the code:


class Beginnermode:

    def __init__(self, level):
        self.enabled = gnipoptions.Beginnermode.Enabled
        if not self.enabled:
            return

    def loop(self):

        self.timer = 0
        self.check = 1
        self.drawTimer = 0

        if not self.enabled:
            return
        if self.timer > self.check:
            self.timer =0
            for p in self.level.planets.values():
                if p.user.n == 0 and p.ships <= p.production:
                    c = (255,255,255)
                    pad = 4
                    screen.circle(c, p.pos, p.r+pad, 6)
        else:
            self.timer += 1


I've worked through every error I got, and eventually got it so I had no errors at all, but it still doesn't work - so i'm starting to think my approach in general is basically wrong. I also had the screen.circle(...) part in a seperate paint() function, but still couldn't get it to work. This is where i'm stuck, i think.

I'm calling the class and function properly (at least I think) as well, with this:     self.Beginnermode = gniputils.Beginnermode(self)

Basically what the code is supposed to do, is put a circle around a planet that's a good value. Eventually i'd extend it so the circles are color coded to assist in value recognition... but i need to get through the basics first. So is there anyone that can push me in the right direction?
post updated on May 6, 2007 @ 10:48pm
Re: More script help for Eckels... :: May 7, 2007 @ 11:31am

Ensign SirGnip

Joined: Dec 27, 2006
Posts: 59
Location: Chi-town

Don't worry about asking questions.  Not everyone has the same experience level with Python and nuthin wrong with that.  The more we help each other, the better the mods in general become (and the more we free up Phil to make cool features).

Ok, two guesses as to why your code isn't drawing a circle.  First, you say you created an instance of your class with this code:

self.Beginnermode = gniputils.Beginnermode(self)

Good.  But, just creating an instance of your object doesn't get it to "run."  You need to make sure your object's loop() and paint() functions get called (my Revolt mod does this in the Level class' loop() and paint() functions, found in the classic.py file).  

Second, to draw a circle in Galcon, you have to use the circle method on the screen object (don't know if you can cal Pygame's drawing methods directly).  The only place I saw in the code to get the screen object is thru the Level's paint() function (which is passed a screen object as a parameter).

So, you need to make sure your object is created, that its loop and paint methods are called (probably from the Level object) and then call screen.circle from within Beginnermode's paint().  That should do it.

To walk before running, just try dropping this line into the paint function in classic.py to see a circle drawn:

screen.circle((256, 0, 0), (300, 200), 50, 6)

You should see a smallish red circle nearish the center of the screen.

Let us know how it goes...
post updated on May 7, 2007 @ 1:06pm
Re: More script help for Eckels... :: May 8, 2007 @ 8:09am

Ensign eckels

Joined: Mar 4, 2007
Posts: 200

To walk before running, just try dropping this line into the paint function in classic.py to see a circle drawn:

screen.circle((256, 0, 0), (300, 200), 50, 6)

You should see a smallish red circle nearish the center of the screen.

Let us know how it goes...


I get an invalid rgba argument.

btw, is there a place I can read more about screen.circle? or is it not something built into python or pygame?
Re: More script help for Eckels... :: May 8, 2007 @ 10:18am

Ensign SirGnip

Joined: Dec 27, 2006
Posts: 59
Location: Chi-town

To walk before running, just try dropping this line into the paint function in classic.py to see a circle drawn:

screen.circle((256, 0, 0), (300, 200), 50, 6)

You should see a smallish red circle nearish the center of the screen.

Let us know how it goes...


I get an invalid rgba argument.

btw, is there a place I can read more about screen.circle? or is it not something built into python or pygame?


Doh!  My bad.  I gave you an invalid color value.  Color values can only be between 0-255.

I meant: 

screen.circle((255, 0, 0), (300, 200), 50, 6)

The screen object and it's circle function are Galcon specific, I think. So, no general docs about it (except what Phil provides).  So, since modding is still in beta, there really isn't much in the way of docs (other than the links in the sticky post at the top of this forum).

But, in my tinkering, here's what the circle() function takes:
1st arg - the red/green/blue color of the circle (each value can be 0-255)
2nd arg - the position of the center of the circle (x, y)
3rd arg - the radius of the circle
4th arg - the width of the line used to draw the circle
post updated on May 8, 2007 @ 10:22am
Re: :: May 8, 2007 @ 11:12am

Ensign philhassey

Joined: Nov 30, 2006
Posts: 761
Location: Zarcon

SirGnip -

Thanks for helping out on that :)  I think you explained it just fine.  BTW - if you (or anyone who uses mods) wants to add some stuff to the http://www.imitationpickles.org/galcon/wiki/Mods_API/ feel free :)  I'll fill it in myself eventually, but if other people fill it in for me, that'll be more time I can spend on getting other stuff done.  

- Phil
post updated on May 8, 2007 @ 11:16am
Re: More script help for Eckels... :: May 8, 2007 @ 6:08pm

Ensign eckels

Joined: Mar 4, 2007
Posts: 200

Don't worry about asking questions.  Not everyone has the same experience level with Python and nuthin wrong with that.  The more we help each other, the better the mods in general become (and the more we free up Phil to make cool features).

Ok, two guesses as to why your code isn't drawing a circle.  First, you say you created an instance of your class with this code:

self.Beginnermode = gniputils.Beginnermode(self)

Good.  But, just creating an instance of your object doesn't get it to "run."  You need to make sure your object's loop() and paint() functions get called (my Revolt mod does this in the Level class' loop() and paint() functions, found in the classic.py file).  

Second, to draw a circle in Galcon, you have to use the circle method on the screen object (don't know if you can cal Pygame's drawing methods directly).  The only place I saw in the code to get the screen object is thru the Level's paint() function (which is passed a screen object as a parameter).

So, you need to make sure your object is created, that its loop and paint methods are called (probably from the Level object) and then call screen.circle from within Beginnermode's paint().  That should do it.

To walk before running, just try dropping this line into the paint function in classic.py to see a circle drawn:

screen.circle((256, 0, 0), (300, 200), 50, 6)

You should see a smallish red circle nearish the center of the screen.

Let us know how it goes...


SirGnip, I did call the function with "self.Beginnermode.loop()". I had it on a line right after your revolt mod. I think it was calling it properly. The biggest problem I was having with the screen.circle was that when it was supposed to be making a circle, it'd get an error because... and I can't remember the exact terminology now, but it was something like "can't find where screen was initialized" 

I couldnt understand why the circle wasn't just being drawn. I still dont think i do, but I did put that line into the draw function in classic.py and it worked there, so i'm going to move my class over to the classic.py file and utilize it's paint function and maybe then it'll work. That's what you call a run-on sentence.

Thanks so much SirGnip for your clear and thorough answers. It's making these first steps much easier. I'm starting to understand it all a bit better.
Re: More script help for Eckels... :: May 8, 2007 @ 6:15pm

Ensign philhassey

Joined: Nov 30, 2006
Posts: 761
Location: Zarcon

I couldnt understand why the circle wasn't just being drawn. I still dont think i do, but I did put that line into the draw function in classic.py and it worked there, so i'm going to move my class over to the classic.py file and utilize it's paint function and maybe then it'll work. That's what you call a run-on sentence.


The game logic is handled separately from the game rendering.  loop() is called each frame - that's where you update what is happening.  event(e) is called each time an event comes it, so that's where you handle events.  paint(s) is called each time Galcon wants to redraw the screen, so that's where you put stuff on the screen.

Hope that helps explain some of those methods.
- Phil
Re: More script help for Eckels... :: May 8, 2007 @ 6:38pm

Ensign SirGnip

Joined: Dec 27, 2006
Posts: 59
Location: Chi-town

Hmmm... not sure why that circle wasn't being drawn on your first attempt.  Maybe this will help you understand what was going on:

* The "circle" function is a method on the "Surface" class.  You can only call circle() on an object of type "Surface"
* "Surface" objects represent surfaces in the game you can draw on.  The main surface is the screen, though there can be more.
* The only way thru a mod (that I know of) to get an object of type "Surface" is thru the Level's paint() method
* in Level's paint() method, an object of type "Surface" is passed into the function.  It's name is "screen".
* So, you can pass this object named "screen" all thru your code and call circle() on it, wherever it is.

Hope this helps...
post updated on May 8, 2007 @ 6:39pm
Re: More script help for Eckels... :: May 8, 2007 @ 6:58pm

Ensign SirGnip

Joined: Dec 27, 2006
Posts: 59
Location: Chi-town

I updated the API wiki page a bit with some of the basic data members:

http://www.imitationpickles.org/galcon/wiki/Mods_API/index.php
Re: More script help for Eckels... :: May 8, 2007 @ 7:37pm

Ensign eckels

Joined: Mar 4, 2007
Posts: 200

ok, here's where I am. Maybe if I you can help me get this completed, then I'll understand what it is i'm missing from the equation...

It looks to me like I've got everything in place to make this work... the only error I'm getting now is "Beginnermode instance has no attribute "planets".

here's the code. I created a new class at the end of the classic.py file.:


class Beginnermode:

    def __init__(self, level):
        self.enabled = gnipoptions.Beginnermode.Enabled
        if not self.enabled:
            return

    def loop(self):
            
        for p in self.planets.values():
        
            while p.user.n == 0:
                if p.user.n == 0 and p.ships <= p.production:
                    self.Beginnermode.paint(screen,p.pos,p.r)

        

    def paint(self,screen,pos,r):
        screen.circle((255, 0, 0), pos, r, 5)


Ok so that's it. I'm calling this code in the init function on classic.py, right after yours:

    def init(self):
        self.revoltMod = gniputils.PlanetRevoltMod(self)
        self.statsLoggingMod = gniputils.StatsLogger(self)
        self.Beginnermode = Beginnermode(self)

So what am i leaving out? Am i not properly looping the loop? do I have to initalize something? I've been stuck on this for hours. keep in mind, i've edited this chunk of code about fifty different ways trying one thing or another, this is just the latest incarnation... but I still don't know what's wrong.
post updated on May 8, 2007 @ 7:38pm
Re: More script help for Eckels... :: May 9, 2007 @ 11:44am

Ensign SirGnip

Joined: Dec 27, 2006
Posts: 59
Location: Chi-town

Ok, a few things...

First, doing "self.Beginnermode = Beginnermode(self)" in classic.py is correct, but it isn't the whole picture.  This creates a "Beginnermode" object and stores it on the Level object with the name "Beginnermode".  Good.  But, now that you created your Beginnermode object, you need to make sure that the loop() and paint() functions are called on your object.  They don't get called automatically, you have to do this yourself.  It sounds like you've been using SirGnip_Revolt as a starting point, so in classic.py, the Level's loop() function should have lines that look something like this:

    # tick the mod objects
    self.revoltMod.loop()
    self.statsLoggingMod.loop()
    self.Beginnermode.loop()

And Level's paint() function should have something like this:

    # draw the revolt mod object
    self.revoltMod.paint(screen)
    self.Beginnermode.paint(screen)

To confirm your functions are being called you can always add a line like "print 'looping...'" in the function and it will print stuff to the Galcon screen as the game is running.  Good for debugging.

You know, I'm going to write out how this code could be so that you have a foundation working.  Then you can build on it.  I usually don't like simply writing code for someone (not great for learning), but I feel this will help get you jumpstarted.

In addition to making sure the code changes above are in, here's what should be working code (didn't have time to test it, though):

class Beginnermode: 

    def __init__(self, level): 
        self.enabled = gnipoptions.Beginnermode.Enabled 

    # loop() isn't needed for this code, but I added it as an example
    def loop(self):
        print 'looping...'

    def paint(self,screen):
        print 'painting...'
        if not self.enabled:
            return
        
        for p in self.planets.values():
            if p.user.n == 0 and p.ships <= p.production:
                screen.circle((255, 0, 0), p.pos, 75, 5) 

Hopefully this will help you get rolling...  Fire away with any questions you have about why I did what I did.

One other thought.  While you're getting the hang of this, you can modify the code in the Level class directly (in classic.py) instead of creating your own class.  Functionally, it is not necessary to have your own class.  It is really just something I did to keep my code separate from what Phil provided.  Once you get code working that you put directly in the Level class, you can always pull it out into your own class afterwards.
post updated on May 10, 2007 @ 9:59am
Re: More script help for Eckels... :: May 9, 2007 @ 9:08pm

Ensign eckels

Joined: Mar 4, 2007
Posts: 200

I'm having problems getting your code to work as well..

The error i'm getting (which is one of the most common errors I was getting with my own code as well) is this:

Beginnermode instance has no attribute "planets"

line 115
        for p in self.planets.values():

I think I understand what this means, but I don't understand where the problem is exactly. Did I have to call a planets function or something? How do I fix this?
Re: More script help for Eckels... :: May 10, 2007 @ 10:52am

Ensign SirGnip

Joined: Dec 27, 2006
Posts: 59
Location: Chi-town

I think I understand what this means, but I don't understand where the problem is exactly. Did I have to call a planets function or something? How do I fix this? 

Dern, I missed that one. Here's the fixed code w/ the explanation below it.  I actually tested this and it runs and does stuff.

class Beginnermode: 

    def __init__(self, level): 
        self.enabled = gnipoptions.Beginnermode.Enabled 
        self.mylevel = level

    # loop() isn't needed for this code, but I added it as an example
    def loop(self):
        pass

    def paint(self,screen):
        if not self.enabled:
            return

        for p in self.mylevel.planets.values():
            if p.user.n == 0 and p.ships <= p.production:
                screen.circle((64, 0, 0), p.pos, 75, 5) 

The problem is that the "planets" list is stored on the Level object.  But, this code "for p in self.planets.values()" is running in your Beginnermode object.  So, Beginnermode knows nothing about "planets".  In order for Beginnermode to know about planets, we have to help it out.  In the line that creates the Beginnermode object, we pass in the Level object by passing in "self", which is the Level object.

self.Beginnermode = Beginnermode(self) 

Then, as the code above creates a new Beginnermode object, Beginnermode's __init__() function is automatically called for us.  In Beginnermode.__init__(), we assign the Level object we are passed to our own variable (self.mylevel) so that we can reference it later to get planets (or any other variable on Level such as users, fleets, etc)

    def __init__(self, level): 
        self.mylevel = level

And, now that we have a Level object (stored in mylevel), we can use it to get the list of planets as seen in this line:

        for p in self.mylevel.planets.values():

Hope this helps...
post updated on May 10, 2007 @ 10:53am
Re: More script help for Eckels... :: May 10, 2007 @ 4:30pm

Ensign eckels

Joined: Mar 4, 2007
Posts: 200

SirGnip, you've been so helpful, I can't thank you enough.

Ok now i've had a lot more time to play with this mod, and i'm further down the road with it... i'm having one dumb issue at the moment.

when I do the following: 

x = (p.ships / p.production)

x is always returned as a whole number.

how can i return x as a floating point integer?

I tried things along the lines of defining valuefactor as a float()... but haven't been successful. I'd like to figure it to four decimal places. (i.e. 0.0000) I've looked through tutorials and python.org's documentation, and have been completely unsuccessful in finding an answer.

Thanks in advance.


EDIT: I should clarify one thing... 

I've also tried this: 
valuefactor = float(p.ships / p.production)

but it will still return only the digits to the left of the decimal point.

for instance (the following is not arranged to be proper code, just for example):

45 / 33 = 1.3636etc. (this is what it should be)
45 / 33 = 1          (this is what the program returns)

how can i make this work? I tried using float, to no avail.

float(45 / 33) = 1.0
post updated on May 10, 2007 @ 5:01pm
Re: More script help for Eckels... :: May 10, 2007 @ 4:55pm

Ensign philhassey

Joined: Nov 30, 2006
Posts: 761
Location: Zarcon

x = (p.ships / p.production)

x is always returned as a whole number.

how can i return valuefactor as a floating point integer?


Try this: x = (float(p.ships) / float(p.production))

(Don't worry - you're not the first person to have this gripe, it's being fixed in the next major release of python.)

- Phil
Re: More script help for Eckels... :: May 10, 2007 @ 5:00pm

Ensign eckels

Joined: Mar 4, 2007
Posts: 200

oh jeez. i should have thought of that.

btw, is that something i'll always have to worry about (in python scripting) or is that some sort of galcon bug?
Re: More script help for Eckels... :: May 10, 2007 @ 5:24pm

Ensign SirGnip

Joined: Dec 27, 2006
Posts: 59
Location: Chi-town

oh jeez. i should have thought of that.

btw, is that something i'll always have to worry about (in python scripting) or is that some sort of galcon bug?

This is a Python wart (not really a bug) and not Galcon.  You can try doing "x = 42/13" in the Python interpreter and you'll get an integer back but do "42.0 / 13" and you'll get a float back.  This is because Python assumes that (only vaguely remember the niggly details of type promotion, etc.) when you are doing math on integers, your result should be the same type (an integer).

Check out http://www.amk.ca/python/writing/warts and look for the heading "Integers and Floats" for a bit more detail on this.

Good luck with the mod!  Looking forward to seeing it!  Glad to be able to help out...
post updated on May 10, 2007 @ 5:27pm
Re: More script help for Eckels... :: May 10, 2007 @ 6:13pm

Ensign eckels

Joined: Mar 4, 2007
Posts: 200

ok, here it is: http://www.imitationpickles.org/galcon/uploads/eckels/beginnermode.zip

It's a rough mod - and i'll probably continue working on it, but I feel the need to show off my lightweight skills... :)

basically what it does is check the actual value of taking a planet, comparing the ships to production, and then displaying a colored ring around the planet. the lighter the green of the ring, the better value it is. red planets aren't values, and shouldn't be taken unless all green planets are taken.

I may add other features to it in the future, but for now it is what it is ;)
Re: More script help for Eckels... :: May 10, 2007 @ 8:59pm

Ensign SirGnip

Joined: Dec 27, 2006
Posts: 59
Location: Chi-town

Nice eckels... After I ran your mod and saw how you had the highlight circles around the planets vary with the planet size, I added the same thing to my recent tinkering.  I had forgotten that planet had a radius member.

Keep it up!

You must sign in to post.

Galcon   Watermelons   Dynamite   The Hairy Chestival
All content of imitation pickles (c) 1999-2008 - Phil Hassey  "we care"