billiards-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Billiards-devel] Programming experiments with Billiards


From: Dimitris Papavasiliou
Subject: Re: [Billiards-devel] Programming experiments with Billiards
Date: Fri, 15 Jan 2010 23:05:42 +0200

Hi,
 
None at all, but I find it quite similar to Python (which I use almost
all the time) so I didn't have much difficulties reading and changing
your code. I could even say that I like it so far.

 That's nice to hear.  Besides it will save me some explaining since you can find your way around the code on your own.  I don't really remember anymore what the heck I've been doing in there anyway.  Billiards was the first application built on top of Techne so it has changed design countless times.
 
In the mean time I set up Billiards as a CVS Project in Eclipse IDE and
started experimenting with your code. I followed the changes you made
for 'options.experiment' and created my own 'option.experiment2', which
creates the initial setting I want. It's a quick hack, so if you can
provide a better solution, I'm all for it.

We should be able to make experiment mode configurable.  The thing to determine is what features it should have.  Facilitating repeatable experiments with logging and possibly without much human intervention seems to be the way to go.  
 
Ok, perfect. This is what I needed.

Now, I tried setting observer's position with something like:
  bodies.observer.longitude = -1.42
  bodies.observer.latitude = -0.71
  bodies.observer.radius = 0.4
  bodies.observer.elevation = math.pi / 2 -
                  bodies.cue.elevation -
                  math.rad (5)

but it didn't work. Basically, I want to change observer's direction
like you do with holding down the left mouse in the looking mode.


 As you've probably seen from the code the way the shot cycle is organised is a state machine.  You can be either looking, aiming or waiting.  Transitions between the looking and aiming state happens when you click on the cueball, aiming changes to waiting once you shoot the ball and waiting to looking once the balls come to rest.  Now each transition is an event and has some hook functions attached to it which you can add to.  The problem is that, since these functions are string keys in a table theres no implied ordering (due to the way Lua tables work) and they fire in more or less random order.  It's not really random but you can't control it either.  This is a pain and I'll have to address it at some point.  One solution would be to use integer keys but then you'd say billiards.cuecollision[3] instead of billiards.cuecollision.cuespeed which isn't as nice.  Anyway your problem is probably caused by the fact that one of my own hooks fires after yours and resets the observer heading back to the way *I* like it.  Pretty annoying innit?  You'll have to sort that out... :)

Ok, this works, but I modified it to:
billiards.cuecollision.cuespeed = function ()
   print (string.format ("Cue velocity: {%f, %f, %f}",
                                 bodies.cue.velocity[1],
                                 bodies.cue.velocity[2],
                                 bodies.cue.velocity[3]));
end

since I don't know that math.length function does.

Well it calculates the length or magnitude of a vector.  So this would result in the speed of the ball in m/s regardless of its direction of motion.   All these additional math functions are defined in moremath.lua which is part of Techne.

I made an interesting observation about billiards.cuecollision.cuespeed.
It is almost always called 3 times and the first time it reports
unusually low numbers:
('f' pressed)
Cue velocity: {-0.000003, 0.000000, -0.000003}
Cue velocity: {-0.000003, 0.000000, -0.000003}
Cue velocity: {-0.000003, 0.000000, -0.000003}
('f' released)
('f' pressed)
Cue velocity: {-5.776280, 0.000000, -5.776280}
Cue velocity: {-5.776280, 0.000000, -5.776280}
Cue velocity: {-5.776280, 0.000000, -5.776280}
('f' released)
('f' pressed)
Cue velocity: {-4.332211, 0.000000, -4.332211}
Cue velocity: {-4.332211, 0.000000, -4.332211}
Cue velocity: {-4.332211, 0.000000, -4.332211}
('f' released)

Ah yes...  Didn't I sort that out?  The problem is that as the stick-ball collision actually lasts more than a single timestep of simulation it is registered more than once.  This doesn't seem to adversely affect the simulation itself (in fact it might be more "realistic") but it calls the hooks more than once.  I thought I had corrected this issue.  I'll have to remeber to do it, shoudn't be a big deal.  
 
Ok, this works as you say.

However, running simulatins/experiments this way still requires manual
human input. Is it possible to somehow do this automatically?
For example: currently, I still have to click on the white ball to go
from looking mode to aiming mode and when I'm in the aiming mode, I have
to press 'f' to launch the stick.

I would like to do those 2 things from the code and be able to run 100s
of experiments without human input.

 There's currently no mechanism I know of that allows you to switch modes programmatically.  It shouldn't be hard to improvise one though.  If you look inside ball.lua you'll see that there are some event nodes linked under each ball (with switch or button nodes on top of them) which catch the mouse clicks on the balls and either switch the active cue ball or enter aiming mode if the clicked ball already is the cue ball.  Just put the code that enters aiming mode in a function of your own and call it from wihtin your script to get rid of the need to manually click the ball.  Next move the cue as you already do to shoot the ball and then wait until you no longer are in waiting mode.  Lather, rinse, repeat.  I'm not sure if this will work but it seems likely.  I'll have to try it out myself when I get the time.  There is one more important problem though.  Even if you pull this off, which should be no big problem, you'll still have to wait for the simulation to take place, in real time.  That is, if you want to perform 100 shots you'll have to wait for them to finish.  You won't have to be in front of the computer though.  There is a parameter called dynamics.timescale if memory serves well which controls the flow of time.  Setting this to 0.5 will make things run in slow motion, at half the "normal" time speed.  Now setting it to 2 or 200 for that matter *should* make things run in fast forward.  But it doesn't work.  Small values like 2 work but anything much higher yields funny results.  I don't know why that is.  It shouldn't behave like that but it does.  I'll have to look into it at some point I suppose...
 
One more thing, is there a hook which is triggered when the ball goes in
the hole?
I would like to use this to set up automatic logging to only log the
outcomes, where the non-cue ball goes in the hole.

Hmmm, I don't remeber actually.  But you can set it up!  There's a node called a box node.  It's actually supposed to be a physical body in the shape of a box.  Look through the code to see how it's used.  Now you can put such a box under the table, that is right under the playing surface spanning the hole table.  Balls won't normally contact it when they're on the table but once they sink into the pocket they will.  You can capture that event in the dynamics.collision hook (look through the code to look how that works).  Think of this box as some sort of laser-beam triggerd trap.  There's two things you need to take care of.  First that the box should stay in place and not fall due to gravity.  You can accomplish that by linking it below and Environment node.  This has the effect that any bodies linked below it are considered part of the "static environment" and won't budge no watter what.  As if they were welded in place.  The other thing is that you don't want the balls to actually bump on the box.  It's supposed to be just a laser-beam grid anyway.  This can be done within your collision hook function.  In there you have to detect whether one of the balls is colliding with your box and if so consider that ball pocketed (whatever that means to you).  When you return from that function you supply some numbers.  These are in order the maximum number of collision points that should be calculated for the two bodies, the coefficient of friction between them, the coefficient of restitution between them, and a sort of spring and damping coefficient if you want to make the contact "soft".  You don't need to specify them all as they have default values.  In fact you only need to return the first one and make it zero so than no contact points are calculated.  So to sum it up:

--  Make bodies "visible".

dynamics.drawvolumes = true

--  Construct our booby-trap.

graph.boobytrap = bodies.environment {
    lasergrid = bodies.box {
        position = {...},
        size = {...},

        -- This has no meaning for a box node.
        -- It's just there for our convinience, see below.

        isbooby = true
    }
}

-- Wire up our triggering and logging circuitry.

dynamics.collision.ispocketed = function (a, b)
    -- There's no guarantee on the order of a and b.

    if a.isbooby and b.isball or
       b.isbooby and a.isball then
        local ball, booby

        ball = a.isbooby and a or b
        booby = a.isbooby and b or a

        -- Do your logging here.

        return 0
    end
end


Maybe this should go into Billiards itself, it is a useful event after all.  *Sigh*.  So much work to do, so little time to do it in.  And Aviation is terribly behind schedule.  Oh well... 
 
Dimitris.

reply via email to

[Prev in Thread] Current Thread [Next in Thread]