Draw a lifebar

651 views
Skip to first unread message

Pascal LE MERRER

unread,
Apr 8, 2012, 5:05:23 PM4/8/12
to cocos-...@googlegroups.com
Hello

I'm stuck with doing something I thought would be trivial.
I want to draw a colored rectangle representing the life points of the player.
I did not find how to do it with cocos2D.
I did not find any way to draw a colored rectangle. Sprites require an image, which can't be cropped or resized along one dimension only (scale affects both height and width).
I'm quite surprised. Did I miss anything ? What would be the best way to do this?

Pascal

claudio canepa

unread,
Apr 8, 2012, 5:49:18 PM4/8/12
to cocos-...@googlegroups.com


Pascal
--
 


An example call to obtain a 64 x 32 pure red rectangle

bar = cocos.layer.ColorLayer(255, 0, 0, 255, width=64, height=32)

Ivo F.A.C. Fokkema

unread,
Apr 9, 2012, 4:30:44 AM4/9/12
to cocos-...@googlegroups.com
Hi Pascal,

I had been dealing with that as well, and couldn't get any better than
this (indeed using ColorLayer, what Claudio already suggested):

In unit's __init__():
(snip)

# Now create a life bar (init, will be updated by updateBar).
nBarWidth = int(self.unit.height * 0.9)
self.oBar = cocos.layer.ColorLayer(0, 0, 0, 255, width=nBarWidth, \
height=2) # Default to black.
self.add(self.oBar, z=2)
# You might want to change the position of the bar, for me
# This position works out nicely.
self.oBar.position = (-self.oBar.width/2, self.unit.width/2)

# Add the text (hitpoints left / total life).
self.oBarText = cocos.text.Label('%d / %d' % (self.nHitPoints, \
self.nLife), font_name='Verdana', font_size=6, color=(255, 255, 255, \
150), anchor_x='left', anchor_y='bottom')
self.oBarText.position = (self.oBar.x, self.oBar.y+1)
self.add(self.oBarText, z=2)
self.updateBar()

Then, updateBar() looks like:
def updateBar (self):
if self.nHitPoints < 0:
self.nHitPoints = 0
nDiv = (float(self.nHitPoints)/self.nLife)
if nDiv >= 0.5:
nGreen = 255
nRed = int((1 - nDiv) * 2 * 255)
else:
nGreen = int(nDiv * 2 * 255)
nRed = 255
# Now draw it.
self.oBar.color = (nRed, nGreen, 0)
self.oBarText.element.text = '%d / %d' % (self.nHitPoints, \
self.nLife)

The bar nicely moves from green to orange to red, if the life of the
unit decreases. However, what I've been struggling with and couldn't
implement, is trying to change the width of the health bar. I couldn't
get that to work. If you find out how, I would be very grateful if you'd
tell me how :)

Good luck on your game!

Ivo

claudio canepa

unread,
Apr 9, 2012, 8:30:10 AM4/9/12
to cocos-...@googlegroups.com
On Mon, Apr 9, 2012 at 5:30 AM, Ivo F.A.C. Fokkema <ivo.f...@gmail.com> wrote:
Hi Pascal, 

I had been dealing with that as well, and couldn't get any better than
this (indeed using ColorLayer, what Claudio already suggested):


[snip]
 
The bar nicely moves from green to orange to red, if the life of the
unit decreases. However, what I've been struggling with and couldn't
implement, is trying to change the width of the health bar. I couldn't
get that to work. If you find out how, I would be very grateful if you'd
tell me how :)

Good luck on your game!

Ivo

 


A second look to ColorLayer shows that width and height changes after object creation don't change the vertexes  associated to the object, so it isn't a good fit to a MetterBar.

But that behavior can be added.

Here a pastebin with two MetterBar versions, one done with plain old open GL inmediate mode, another by subclassing ColorLayer


claudio

--

   

Philippe

unread,
Apr 9, 2012, 2:54:56 PM4/9/12
to cocos2d discuss
could also draw a white rectangle using PIL
then using it to create a sprite
use that sprite .color to change the color.

something like

import Image
im = Image.new('RGBA', (600, 50), (255, 255, 255, 255))
im.save('from_pil/life.png')

...

class Life(Sprite):

def __init__(self):
super(Life, self ).__init__('from_pil/life.png')
self.colors = [(51, 198, 244), (248, 152, 29), (237, 32, 36)]
self.color = colors[0]

def update_color(self, v):
self.color = self.colors[v]


On Apr 9, 2:30 pm, claudio canepa <ccanep...@gmail.com> wrote:

Pascal LE MERRER

unread,
Apr 9, 2012, 3:09:19 PM4/9/12
to cocos-...@googlegroups.com
Hello

Thanks for all of your responses.

After Claudio first response, I have implemented a solution which is very similar to Ivo's one, excepted I recreate the layer each time the life points change, to allow its width to change.
It works, and will certainly be enough for this game, but I feel it's a bit limited (and I don't even talk of the cost of the solution, which implies to create a new object each time points change).
By example I can't use a gradient as a background color for my lifebar, and crop it as the life points decrease.

I will have a look on Claudio second proposal, but it seems more complicated for a Cocos2d/OpenGL newbie as me.



claudio canepa

unread,
Apr 9, 2012, 4:49:13 PM4/9/12
to cocos-...@googlegroups.com
On Mon, Apr 9, 2012 at 4:09 PM, Pascal LE MERRER <pascal....@gmail.com> wrote:
Hello

Thanks for all of your responses.

After Claudio first response, I have implemented a solution which is very similar to Ivo's one, excepted I recreate the layer each time the life points change, to allow its width to change.
It works, and will certainly be enough for this game, but I feel it's a bit limited (and I don't even talk of the cost of the solution, which implies to create a new object each time points change).

You are right about the cost

 
By example I can't use a gradient as a background color for my lifebar, and crop it as the life points decrease.


That is doable by further modification of classes I proposed, but needs some openGL  or pyglet batches knowledge. 
 
I will have a look on Claudio second proposal, but it seems more complicated for a Cocos2d/OpenGL newbie as me.



You can play a little with the script I posted to be sure you know the meaning of creation parameters and how to tell the object to display some value, then copy paste the class definition and treat that code as a black box . It will work even if you don't know the details, the same as sprites work even when not knowing all the internal details.

You can even aproximate the gradient feature you want with n NakedBarMetter s side by side in x axis, each with his own color, as childs of a NakedBarMetterMulticolor that will receive the on_update_value from the game and send appropriate messages to the childs.

Someone dares a try ? :)

claudio

--

 

Philippe

unread,
Apr 10, 2012, 4:26:52 AM4/10/12
to cocos2d discuss
can also clip the sprite
http://groups.google.com/group/cocos-discuss/browse_thread/thread/bd464ec0d656fc66#


On Apr 9, 10:49 pm, claudio canepa <ccanep...@gmail.com> wrote:
> On Mon, Apr 9, 2012 at 4:09 PM, Pascal LE MERRER
> <pascal.lemer...@gmail.com>wrote:

Ivo F.A.C. Fokkema

unread,
Apr 10, 2012, 4:51:39 PM4/10/12
to cocos-...@googlegroups.com
Excellent, Claudio!

Using your second implementation (subclassing ColorLayer) I could extend
my existing life bar that was already changing color based on the
percentage of life left, to one that also gets shorter or longer
depending on the life left :)

If somebody wants to see a working example I would probably need to
clean up the code a bit and isolate the needed lines of code from the
rest and put it into one test file, let me know if anyone is interested.

Regards,

Ivo

claudio canepa

unread,
Apr 10, 2012, 10:20:00 PM4/10/12
to cocos-...@googlegroups.com
On Tue, Apr 10, 2012 at 5:51 PM, Ivo F.A.C. Fokkema <ivo.f...@gmail.com> wrote:
Excellent, Claudio!

Using your second implementation (subclassing ColorLayer) I could extend
my existing life bar that was already changing color based on the
percentage of life left, to one that also gets shorter or longer
depending on the life left :)


Good!
 
If somebody wants to see a working example I would probably need to
clean up the code a bit and isolate the needed lines of code from the
rest and put it into one test file, let me know if anyone is interested.


I want !
 
Regards,

Ivo

 

Cheers
 

Ivo F.A.C. Fokkema

unread,
Apr 11, 2012, 5:35:37 PM4/11/12
to cocos-...@googlegroups.com

Alright, see attached! It's running in the test directory. It's not
super clean code, and I actually still have a hack there to make the
lifebar disappear when the unit dies, but oh well... you get the idea.

Ivo

test_lifebar.py

claudio canepa

unread,
Apr 12, 2012, 1:00:48 AM4/12/12
to cocos-...@googlegroups.com
On Wed, Apr 11, 2012 at 6:35 PM, Ivo F.A.C. Fokkema <ivo.f...@gmail.com> wrote:


Alright, see attached! It's running in the test directory. It's not
super clean code, and I actually still have a hack there to make the
lifebar disappear when the unit dies, but oh well... you get the idea.

Ivo

 

Looks good on screen.

The parts for text and color are small and clear.

What looks bad is that both Unit and LifeBar are fidling with the presentation of life value.
Moving the color, text and background logic from Unit to LifeBar  would left the responsibility of life value presentation entirely to LifeBar, which is good for separation of concerns.

I noticed you included in your code a 'copyright <my name>' for a class I posted in this thread. Don't do that please. I understand it was meant as a credit, but it hinders code reuse,  and annoys people.
Just saying, not mad at it.

cheers!

claudio

--
 
 

Ivo F.A.C. Fokkema

unread,
Apr 12, 2012, 5:21:00 PM4/12/12
to cocos-...@googlegroups.com

> What looks bad is that both Unit and LifeBar are fidling with the
> presentation of life value.
> Moving the color, text and background logic from Unit to LifeBar
> would left the responsibility of life value presentation entirely to
> LifeBar, which is good for separation of concerns.

Thanks for your comments! You are completely right of course, I never
had a separate class for it, until I included your implementation. Of
course I should move the "old" updateBar() function and the other life
bar related code in the Unit class to the LifeBar object. I just quickly
put this together, but I'll put it on my to do list :)

I've been working on this game on and off for the last 3 years, so by
the current speed, you can expect a fully functional game with clean
code by 2016 ;)

> I noticed you included in your code a 'copyright <my name>' for a
> class I posted in this thread. Don't do that please. I understand it
> was meant as a credit, but it hinders code reuse, and annoys people.
> Just saying, not mad at it.

Is it the (c) specifically or the fact that your name is there?
Personally I think it's only just to credit the original authors, and it
never hinders me, but I'm just one person of course :)

Regards,

Ivo


claudio canepa

unread,
Apr 12, 2012, 9:17:28 PM4/12/12
to cocos-...@googlegroups.com
On Thu, Apr 12, 2012 at 6:21 PM, Ivo F.A.C. Fokkema <ivo.f...@gmail.com> wrote:

 

I've been working on this game on and off for the last 3 years, so by
the current speed, you can expect a fully functional game with clean
code by 2016 ;)

 
Hope it will be earlier  
 


> I noticed you included in your code a 'copyright <my name>' for a
> class I posted in this thread. Don't do that please. I understand it
> was meant as a credit, but it hinders code reuse,  and annoys people.
> Just saying, not mad at it.

Is it the (c) specifically or the fact that your name is there?

The (c) thing specifically
 
Personally I think it's only just to credit the original authors, and it
never hinders me, but I'm just one person of course :)


Yes, I usually credit in comments the sources of inspiration or borrowed snippets, but not as formal as (c).
 
Regards,

Ivo


cheers

claudio

--


Ivo F.A.C. Fokkema

unread,
Apr 15, 2012, 5:23:36 PM4/15/12
to cocos-...@googlegroups.com
On Thu, 2012-04-12 at 22:17 -0300, claudio canepa wrote:

> On Thu, Apr 12, 2012 at 6:21 PM, Ivo F.A.C. Fokkema
> <ivo.f...@gmail.com> wrote:
>
>
>

(snip)

> > I noticed you included in your code a 'copyright <my name>'
> for a
> > class I posted in this thread. Don't do that please. I
> understand it
> > was meant as a credit, but it hinders code reuse, and
> annoys people.
> > Just saying, not mad at it.
>
>
> Is it the (c) specifically or the fact that your name is
> there?
>
>
> The (c) thing specifically

OK, thanks! I will leave it out next time :)

Regards,

Ivo


Nitneroc

unread,
Jun 12, 2012, 4:22:42 PM6/12/12
to cocos-...@googlegroups.com
I reused your code, claudio, because I'm having fun with a grid-based game where some cells can be filled with water at different levels.
My problem is that I will display many of those (in a big grid) and want them to be batchable. I'm sorry but I can't find any help on how to make something batchable. 

here is a crude attempt : http://pastebin.com/7FYWrDA6
The water_block will not be displayed if added to a BatchNode, but will be displayed ok when added to a regular Node...

Could someone enlighten me ?

claudio canepa

unread,
Jun 13, 2012, 10:59:00 AM6/13/12
to cocos-...@googlegroups.com
On Tue, Jun 12, 2012 at 5:22 PM, Nitneroc <corent...@gmail.com> wrote:
I reused your code, claudio, because I'm having fun with a grid-based game where some cells can be filled with water at different levels.
My problem is that I will display many of those (in a big grid) and want them to be batchable. I'm sorry but I can't find any help on how to make something batchable. 

here is a crude attempt : http://pastebin.com/7FYWrDA6
The water_block will not be displayed if added to a BatchNode, but will be displayed ok when added to a regular Node...

Could someone enlighten me ?


Sorry if this will come too concise, but here we go:

Pyglet batchs groups a bunch of vertexes to draw them in a single call.
Your code is must update vertex coordinates, and the vertex coordinates should be in the same coordinate system.

In cocos three ways to use batches can be seen:

  + The tilemap way: have a private batch that uses a bunch of sprites.
     Look at cocos.tiles class MapLayer.
     Here updating vertex lists is done by manipulating the sprites

   + The ColorLayer way: have a private batch and maintain directly the vertex list. 

   + The cocos.draw way: have one BatchNode which holds a pyglet batch and many childs that are BatchableNodes ; each child updates only a subset of vertex list, the vertexes should be in BatchNode coordinates. IOW, to update vertex list a BatchNode should consider position, rotation, scale. Designing to have rotation=0 and scale=1 simplifies things. If position in the parent BatchNode coordinates, as usually in grids, dont change after creation, then providing vertexes is too much complicated.

Going to your code, you are trying to mix approach 2 and 3, and that does not work.

I pasted an incomplete batched implementation in the third style that may help you:   http://pastebin.com/Uh1uVDg3

Look at the big description there for some ideas.

claudio

--


claudio canepa

unread,
Jun 13, 2012, 11:22:52 AM6/13/12
to cocos-...@googlegroups.com
On Tue, Jun 12, 2012 at 5:22 PM, Nitneroc <corent...@gmail.com> wrote:
I reused your code, claudio, because I'm having fun with a grid-based game where some cells can be filled with water at different levels.


Another option would be to use the cocos.draw module. See the sample
test\test_draw.py

 

Nitneroc

unread,
Jun 25, 2012, 3:46:35 PM6/25/12
to cocos-...@googlegroups.com
Sorry for not replying earlier, I've been overwhelmed by work, recently.

Thank you very much for your explanations and links ! I'll give it a try as soon as possible !

Le mercredi 13 juin 2012 17:22:52 UTC+2, Claudio Canepa a écrit :

Nitneroc

unread,
Jun 27, 2012, 3:46:03 PM6/27/12
to cocos-...@googlegroups.com
Thanks again claudio ! The code you supplied was excellent. You were right not to include ancestors rotations, scaling etc... I'll implement what I need (I'm not sure I need any of this, actually). You really helped me a lot.

Nitneroc

unread,
Aug 1, 2012, 10:11:08 AM8/1/12
to cocos-...@googlegroups.com
Is there a way to add z-ordering to this Water_Block class ? I'm sorry for asking yet another question, but I could'nt find a way by myself.
If there is no easy way, I'll just add those Water_Blocks to a different Layer.

claudio canepa

unread,
Aug 1, 2012, 10:23:49 AM8/1/12
to cocos-...@googlegroups.com
On Wed, Aug 1, 2012 at 11:11 AM, Nitneroc <corent...@gmail.com> wrote:
Is there a way to add z-ordering to this Water_Block class ? I'm sorry for asking yet another question, but I could'nt find a way by myself.
If there is no easy way, I'll just add those Water_Blocks to a different Layer.
--

Currently the z order is mandated by:
   The parent-child relationship between nodes
   The z parameter you can pass in cocosnode.add( child, z=...)

and the method CocosNode.visit uses that info to drive the render.
Look at it to see if your use case can be managed with explicit z.
 


Nitneroc

unread,
Aug 1, 2012, 3:25:33 PM8/1/12
to cocos-...@googlegroups.com

Currently the z order is mandated by:
   The parent-child relationship between nodes
   The z parameter you can pass in cocosnode.add( child, z=...)

and the method CocosNode.visit uses that info to drive the render.
Look at it to see if your use case can be managed with explicit z.

I can make some of those Bars you created go in front of others, but I can't make them go in front of a sprite. Here's a test code :
You'll need an image.png file next to the script. I can't make this Sprite go behind a Bar with a simple z argument.

As you suggested, I looked at CocosNode.visit, and it seems perfect for z-ordering, yet this code is using a BatchNode, which doesn't seem to care about z-ordering :
def visit(self):
        """ All children are placed in to self.batch, so nothing to visit """
        glPushMatrix()
        self.transform()
        self.batch.draw()
        glPopMatrix()

So I guess it's the pyglet.graphics.Batch that has to take care of ordering. The code here is much too hard for me but I think it works with groups (that work like z-ordering).
I found this message somewhere : http://www.mail-archive.com/pyglet...@googlegroups.com/msg03884.html, and I tried using pyglet.graphics.OrderedGroup, but I still didn't manage to make it work.

I think the best (easiest) way will be to put those bars in their own layer with the z value I want.
Reply all
Reply to author
Forward
0 new messages