Dynamically draw lines

Hi again,

have some trouble to set up an dynamically render.drawLine - position the selection Circle at end of line for each circle (get only one position)

some Demo:

choice_test.blend (647 KB)

code:



'''
dynamically draw_line by the_cannibal
'''

from bge import logic, render
#from mathutils import * #nicht diesmal :)

def xrange(obj, start, stop, step):
    if not "xrange" in obj:
        obj["xrange"] = start
    if obj["xrange"] < stop:
        obj["xrange"] += step
        return (obj["xrange"], False)
    else:
        obj["xrange"] = start
        return (obj["xrange"], True)

def get_points(own, scene_objects, name):
        point_list = []
        
        for a in scene_objects:
            if name in str(a):
                point_list.append(str(a))    
        return sorted(point_list)


def draw_function(own, scene_obj, s_c_list, point1, point2):
    
    if own["reverse"] == 0:
        counter, indicator = xrange(own, 0.0, 1.0, 0.005)
    elif own["reverse"] == 1:
        counter, indicator = xrange(own, 0.0, 1.0, 0.005)
        counter = ((counter/-1) +1)
    
    if indicator == False:
        draw_point = point1.lerp(point2, counter)
        render.drawLine(draw_point, point2, (1.0, 1.0, 1.0))
        for sc in s_c_list:
            scene_obj.from_id(sc).worldPosition = draw_point
            #print(draw_point)

        return False
    else:
        return True
    
def draw_f_t(own, scene_obj, s_c_list, point1, point2, point3):
    if own["reverse"] == 0:
        if own["draw_system"] == 0:
            back_drawn_1 = draw_function(own, scene_obj, s_c_list, point1, point2)
            draw_line(point2, point3)
            if back_drawn_1 == True:
                own["draw_system"] = 1
        if own["draw_system"] == 1:
            back_drawn_2 = draw_function(own, scene_obj, s_c_list, point2, point3)
            if back_drawn_2 == True:
                own["draw_system"] = 2
                return True

    elif own["reverse"] == 1:
        if own["draw_system"] == 0:
            back_drawn_1 = draw_function(own, scene_obj, s_c_list, point2, point3)
            if back_drawn_1 == True:
                own["draw_system"] = 1
        if own["draw_system"] == 1:
            draw_line(point3, point2)
            back_drawn_2 = draw_function(own, scene_obj, s_c_list, point1, point2)
            if back_drawn_2 == True:
                own["draw_system"] = 2
                return True
    
def draw_line(point1, point2):
    render.drawLine(point1, point2, (1.0, 1.0, 1.0))

def add_circle(own, scene_obj, add_obj, points, count):
    if not "state_once" in own:
        own["state_once"] = 0
        own["selection_obj_list"] = []
    if not own["state_once"] == count:
        for a in points:
            if "_C" in a:
                new_obj = add_obj("choice_Circle", None, 0)
                new_obj.worldPosition = scene_obj[a].worldPosition
                own["selection_obj_list"].append(id(new_obj))
                own["state_once"] += 1
                
    return own["selection_obj_list"]

def draw_selection_circle(cont):

    own = cont.owner
    scene = logic.getCurrentScene()
    scObj = scene.objects
    addObj = scene.addObject
    num_0 = cont.sensors["num_0"].positive
    num_1 = cont.sensors["num_1"].positive

    grouplist = ["main_color_Point", "spoiler_Point", "exhaust_Point", "suspension_Point", "hover_wheel_Point", "under_light_Point"]

#    grouplist.remove("spoiler_Point")

    if num_0:
        own["acti"] = 0
    elif num_1:
        own["acti"] = 1
        own["draw_system"] = 0
    
    if own["acti"] == 0:
        for p in grouplist:
            points = get_points(own, scObj, p)
            selection_circle_list = add_circle(own, scObj, addObj, points, len(grouplist))
                
            point_1 = scObj[points[0]].worldPosition
            point_2 = scObj[points[1]].worldPosition
            point_3 = scObj[points[2]].worldPosition

            stt = draw_f_t(own, scObj, selection_circle_list, point_1, point_2, point_3)

            if stt == True:
                own["acti"] = 1
    else:
        for p in grouplist:
            points = get_points(own, scObj, p)
            
            point_1 = scObj[points[0]].worldPosition
            point_2 = scObj[points[1]].worldPosition
            point_3 = scObj[points[2]].worldPosition
            
            draw_line(point_1, point_2)
            draw_line(point_2, point_3)
 

In line 39 you move all six points with “scene_obj.from_id(sc).worldPosition = draw_point” to the same position.

@HG1
of course but how can I avoid this? I have to get all possible points to the specific circle but, how?

You already loop over all objects (lines) in line 108. So looping over all points in line 38 is wrong. Looping over all points would only work if you do this outside the first loop and calculate the lerp individually for this objects.

But I think it is better to do the draw in the draw function, so we don’t need to calculate the position (lerp) again.
What I have changed.

  1. To add object directly instead of the id of the circles to the list. The id is not necessary it is easier to get the object directly from the list and we also don’t need the scene obj anymore.
  2. The remove the second loop and pass an index (instead of scene obj) to the draw function.
  3. Use the index to get and move the correct object.

'''
dynamically draw_line by the_cannibal
'''

from bge import logic, render
#from mathutils import * #nicht diesmal :)

def xrange(obj, start, stop, step):
    if not "xrange" in obj:
        obj["xrange"] = start
    if obj["xrange"] < stop:
        obj["xrange"] += step
        return (obj["xrange"], False)
    else:
        obj["xrange"] = start
        return (obj["xrange"], True)

def get_points(own, scene_objects, name):
        point_list = []
        
        for a in scene_objects:
            if name in str(a):
                point_list.append(str(a))    
        return sorted(point_list)


def draw_function(own, i, s_c_list, point1, point2):
    
    if own["reverse"] == 0:
        counter, indicator = xrange(own, 0.0, 1.0, 0.005)
    elif own["reverse"] == 1:
        counter, indicator = xrange(own, 0.0, 1.0, 0.005)
        counter = ((counter/-1) +1)
    
    if indicator == False:
        draw_point = point1.lerp(point2, counter)
        render.drawLine(draw_point, point2, (1.0, 1.0, 1.0))
        s_c_list[i].worldPosition = draw_point

        return False
    else:
        return True
    
def draw_f_t(own, i, s_c_list, point1, point2, point3):
    if own["reverse"] == 0:
        if own["draw_system"] == 0:
            back_drawn_1 = draw_function(own, i, s_c_list, point1, point2)
            draw_line(point2, point3)
            if back_drawn_1 == True:
                own["draw_system"] = 1
        if own["draw_system"] == 1:
            back_drawn_2 = draw_function(own, i, s_c_list, point2, point3)
            if back_drawn_2 == True:
                own["draw_system"] = 2
                return True

    elif own["reverse"] == 1:
        if own["draw_system"] == 0:
            back_drawn_1 = draw_function(own, i, s_c_list, point2, point3)
            if back_drawn_1 == True:
                own["draw_system"] = 1
        if own["draw_system"] == 1:
            draw_line(point3, point2)
            back_drawn_2 = draw_function(own, i, s_c_list, point1, point2)
            if back_drawn_2 == True:
                own["draw_system"] = 2
                return True
    
def draw_line(point1, point2):
    render.drawLine(point1, point2, (1.0, 1.0, 1.0))

def add_circle(own, scene_obj, add_obj, points, count):
    if not "state_once" in own:
        own["state_once"] = 0
        own["selection_obj_list"] = []
    if not own["state_once"] == count:
        for a in points:
            if "_C" in a:
                new_obj = add_obj("choice_Circle", None, 0)
                new_obj.worldPosition = scene_obj[a].worldPosition
                print (new_obj)
                own["selection_obj_list"].append(new_obj)
                own["state_once"] += 1
                
    return own["selection_obj_list"]

def draw_selection_circle(cont):

    own = cont.owner
    scene = logic.getCurrentScene()
    scObj = scene.objects
    addObj = scene.addObject
    num_0 = cont.sensors["num_0"].positive
    num_1 = cont.sensors["num_1"].positive

    grouplist = ["main_color_Point", "spoiler_Point", "exhaust_Point", "suspension_Point", "hover_wheel_Point", "under_light_Point"]

#    grouplist.remove("spoiler_Point")

    if num_0:
        own["acti"] = 0
    elif num_1:
        own["acti"] = 1
        own["draw_system"] = 0
    
    if own["acti"] == 0:
        for i, p in enumerate(grouplist):
            points = get_points(own, scObj, p)
            selection_circle_list = add_circle(own, scObj, addObj, points, len(grouplist))
                
            point_1 = scObj[points[0]].worldPosition
            point_2 = scObj[points[1]].worldPosition
            point_3 = scObj[points[2]].worldPosition

            stt = draw_f_t(own, i, selection_circle_list, point_1, point_2, point_3)

            if stt == True:
                own["acti"] = 1
    else:
        for p in grouplist:
            points = get_points(own, scObj, p)
            
            point_1 = scObj[points[0]].worldPosition
            point_2 = scObj[points[1]].worldPosition
            point_3 = scObj[points[2]].worldPosition
            
            draw_line(point_1, point_2)
            draw_line(point_2, point_3)

I really like it when I can exit a game without killing Blender. Please do not provide sample files with deactivated ESC.

I looked at your blend. I was even starting a post, but to be honest your code is too complex too me. There are too many things I need to wildly guess. To me this code is only maintainable by you as you know what it should do (even when it does not do that).

Just to let you know the questions I get from a quick look:

  • Why does draw_selection_circle not draw a circle?
  • What means f and a t? -> see draw_f_t()
  • What means draw_system? 0,1,2 are numbers to me
  • What means acti? what means 0,1 in this context
  • What means state_once? what means the number
  • What means reverse? what means 0,1? I expect at True,False
  • What means xrange? Which magically transforms into counter and indicator.
  • What means indicator? True, False means what?
  • What means s_c_list? A list of s and c?
  • What is sc and scObj? see above
  • What means draw_function? This draws a function? Or does it means it draws?
  • What means back_drawn_1? (especially as it is the result of “draw_function”)
  • What means back_drawn_2? What is the difference to back_drawn_1? Why it has a number in hte name?
  • Why you perform a condition check of a boolean value against a boolean constant? The result is boolean too [if indicator == True is the same as if x indicator]
  • Why you create an alias to “addObject” especially with name like “addObj”? Why you transfer this function as argument? I do not see that you offer any alternative to addObject. This means you can hardcode it and remove the argument “addObject”. This will reduce the complexity of your code.
  • What means stt?

easier to understand is:

  • counter - I assumes it contains the current counter value
  • get_points - lets me assume I get some kind of points.
  • draw_point - let me assume it means the current point to draw (somehow)
  • point1, point2 - I would prefer some sort of from/to or begin/end or start/end but I think I guess what is meant
  • scene_obj - no good name, But I assume you mean a game object rather than a scene (you have just one)
  • own - I do not like “own” as it implies “owning” rather than “owner”, but I can guess what you mean
  • a (in points) - it is ok as it is used in closed context. A better name would be point (as it is an item of points)
  • count - I assume it contains a count of something
  • groupList - I’m not sure. The name implies a list of groups. Are that groups? Or at least group names?
  • p - ok in close context. But I do not see a relation to groupList. Why not at least “g”?

I know all this questions do not help you on your problem. Unfortunately I’m not able to help you until I find answers on this questions. You know the answers right now. Are you sure you know them later?

Now this post is large again :rolleyes:.

Btw. Are you sure that “manually drawing” is what you want? I mean you need to refresh the draw each frame. This adds up pretty fast.

@HG1 thank you to correct my script/modul it works fine.

@Monster
I understand what you want to say to me and yes, I should be careful with names for “some things” but, I have to rework the code because this is only a development state nothing has to be “perfect”. But thanks for the hints you gave to me.

ps: I didn’t like single letters in important values, did you now what means “g” if the code getting bigger?

have rework the key to “ENTER”/“RETURN” because if you play a game and hit ESC the game bring (most of all) up an Menu and didn’t close :slight_smile:

some image where I use it there are more than 5 models and each models have an customization menu and i did not want to animate all of this lines for each model

some example (not finished):


I suggest to animate one line and replicate it 5 times. This is much simpler.

Referring to your image I think you can easily work with a few meshes. You can get the lines by setting the material to wireframe and shadeless.

This way you can create an action to get the animation. There are several different options from animating scale to shape key to armature.

You can even use two objects to represent horizontal and diagonal lines. The circle (can be wireframe too) can be placed at the target location.

I think this is less complicated than what you already have. The objects do not need to be refreshed as they are present already.

(Imagine you want to try how it looks when you animate from the circles to the labels, rather than the other way around. How much effort would you need ;)).

Maybe this is an alternative.

yes it isn’t the best and easiest way, but the dynamically way I animate only the positions/scale of the empties “points” and let it go so I don’t have to animate the complete line roll from “A” over “B” to “C”.

for the graphic and logic use isn’t it a real impact so it will be only simpler for me :smiley:

ps: if wireframe draw a single edge? I think this need a face.

You just need a single triangle. You can place two vertices at the same position to get a thickness of a single line.

thanks didn’t know that