[Top][All Lists]
[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: |
Thu, 14 Jan 2010 12:15:56 +0200 |
Hello Tadej,
what you want to do makes sense and should be
possible relatively easily. In fact, it was what Billiards was
designed for. There will be some scripting involved though. How much
Lua do you know?
The initial setting you describe would be a bit of a problem right
now. It's fairly easily done by hacking the internals of Billiards but
not by just *adding* some code as it should be done. During the
development of Billiards I needed to perform some experimentation in
order to determine whether the physics simulator actually produced the
correct results (to my surprise, it actually did without requiring any
special tweaking). So I created an experimentation mode which featured
only one white ball on a Carom table. You could then easily perform
squirt experiments etc. That's all I needed back then but it seems now
that I'll have to expand experimentation mode so that you can somehow
describe which balls you want at startup and where you want them
placed. I should be able to make the necessary changes soon so I'll
send you a patch and instructions on how to do what you want then. In
the meantime, let's focus on the rest. (You can start Billiards in
experimentaion mode btw with the -Oexperiment flag).
Now regarding the second point: sidespin, folllow and elevation
should be easy to setup but "shot force" is not really. The problem is
that it's difficult to even define what this "shot force" would be.
During the short time that collision between the cue tip and ball takes
place a force is exerted on the ball by the tip but as all impact
forces it's hard to determine what it is and it's not constant anyway.
This is in the "simple" case where the tip or ball does not flex, which
of course does happen. So in short you can apply a force to the ball
at a specific offset and elevation instead of actually whacking it with
the cue but this would probably not produce the desired results. If
however all you need is to be able to perform a set of shots with the
same force or with "more" or "less" force there are things you can do.
Let's take it from the top. I'll be as brief as possible assuming you
only want to know as much as absolutely necessary to be able to
implement what you describe. If you need more detail let me know.
I'll be happy to provide it as I need to write a manual on how to
program Billiards and Techne at some point anyway.
Billiards uses the concept of hooks to perform certain actions at
certain events. Events can be, for example the fact that the player
lines up a shot (starts aiming), takes a shot when two balls collide or
when a ball bumps agains the cushions etc. When these happen certain
functions are called to perform some tasks. These functions can be
assinged by Billiards (that is by me) or by the user (and that would
be you). For example when you click on the cueball to start aiming all
functions associated with the "aiming" hook are called and amongst them
the following which you can find inside game.lua which should reside in something like /usr/local/share/techne/billiards:
billiards.aiming.reset = function ()
graph.transition = transitions.dissolve {
duration = 0.7
}
bodies.cue.elevation = 0
bodies.cue.sidespin = 0
bodies.cue.follow = 0
bodies.observer.longitude = bodies.cueball.position[1]
bodies.observer.latitude = bodies.cueball.position[2]
bodies.observer.radius = 0.4
bodies.observer.elevation = math.pi / 2 -
bodies.cue.elevation -
math.rad (5)
end
What this does is fade the screen to provide a nice
transition, reset the elevation, and offsets to zero degrees (or was
that radians) and meters respectively and to setup the observer (that
is the "camera") how it should be (or how I like it if you prefer). Now
if you want to change some of this, presumably the shot parameters the
best way to go about it would be this:
local oldreset
oldreset = billiards.aiming.reset
billiards.aiming.reset = function ()
-- First call the old function to setup the default
-- behavior we don't want to change.
oldreset()
-- Now change what we don't like.
bodies.cue.elevation = math.pi/4
bodies.cue.sidespin = billiards.ballradius * 0.3
bodies.cue.follow = -0.003
end
You may be wondering where to put that code but we'll get to that
later. Now setting up the shot is another matter. The whole world in
Billiards (actually as small as a room with no walls and a pool table)
is set up of nodes connected in a graph, sort of like a tree. The
whole graph is traversed (several times actually per frame) and certain
actions are performed by each node according to its nature. For
example a node representing a physical body might perform collision
detection and physical simulation for this frame, a node representing a
visible surface (of a ball conveniently enough) might draw itself on
the screen. Now there also happens to be a node representing a
"slider" that is a joint between two bodies which allows them to slide
against each other along a certain axis. This node actually links the
cue stick with your hand (which is not drawn) and can also be powered,
as if by a motor, which in the real world would be your right arm. So
this joint is called joints.arm and the parameters of its motor are set like so:
joints.arm.motor = {v, F_max}
What
this actually means is that you want the motor to power the bodies it's
linked to in such a way that their relative velocity along the joint's
axis becomes v and in order to do this it can exert a force on the bodies no larger than F_max. In our case, since the hand is considered fixed, this means that your right arm can push the stick with no more than F_max newtons of force in order for the tip to reach and maintain a velocity of v m/s. The stick needs to be accelerated to that velocity though so the larger the force the sooner it will speed up to v.
So if you use the same motor parameters and the same initial position
for the stick relative to the ball (this latter comes into play
because, if F_max
is too low the stick might hit the ball before it has the time to reach
the target velocity), if therefore both these conditions hold then the
stick will contact the ball with the same velocity and provide
identical (more or less, hopefully more more than less) results between
shots. Raising v and making F_max
large enough to reach it should result in more energy being transferred
between the balls and cue. Incidentally there's a hook called billiards.cuecollision
I believe which calls its functions right before the cue collides with
a ball. You can use that to measure the velocity of the cue stick at
that moment to make sure it is what you want it to be. The cue is
described by the node bodies.cue and its velocity can be read at bodies.cue.velocity so you can write:
billiards.cuecollision.cuespeed = function()
print (math.length (bodies.cue.velocity))
end
So
what you would presumably want would be to be able to hit a key and
have the stick launch to reach a certain speed before hitting the
ball. You need to bind some code to a key and you can use a node to do
that. There's a node called an event node. When this is traversed it
queries the windowing system for input events and fires hooks for each
one. So you need to define such a node and link it to the tree
somewhere (where exactly is not important as long as you don't, by
chance, overwrite one of my nodes). Do it like this:
graph.launcher = frames.event {
keypress = function (self, key)
if key == 'f' then
-- Substitute suitable values here.
joints.arm.motor = {v, F_max}
end
end
}
Moving
on to the third point. You only want the final positions so you need
to measure them once the shot is over. There is no "finished" event
and hook but there are "waiting" and "looking" events. (You start
waiting as soon as you strike the cue ball and when these come to a
rest you start looking once more to decide upon your next shot). You
could use hooks for both these events to detect a transition between
them or alternatively I could introduce a "finished" event which would
be as simple. But I suppose the best way to go would be to bind the
logging to a key so that you have more control over it. You can
consult the lua manual to find out how to open a file and write to it.
I'll just provide some sample code to print it on the terminal:
graph.logger = frames.event {
keypress = function (self, key)
if key == 'l' then
for i, ball in bodies.balls do
print (string.format ("%d: {%f, %f, %f}\n", i,
ball.position[1],
ball.position[2],
ball.position[3]));
end
end
end
}
As you can see bodies.balls is actually a table with all the ball
nodes inside. You traverse this and for each ball node you print it
position vector. Simple enough I believe. After the shot is over and
logged you need to reset the balls to their initial positions probably
and this can be done by setting their postion in much the same way as
you printed it:
bodies.balls[1].position = {x_w, y_w, billiards.ballradius}
bodies.balls[2].position = {x_b, y_b, billiards.ballradius}
You can put this code right after the logging takes place if
you want. This is more or less it for now. One thing that remains to
be mentioned is where to put all this code. You can actually specify
additional script files for Billiards (or rather Techne) to run with
the -c switch. So put all your code in a script file called, say experiment.lua and put this in say ~/foo. You can then run it like this:
billiards -c ~/foo/experiment.lua
I
should also say that all the code above has either been copied from
Billiards' source or written on-the-fly and hasn't been tested at all,
as I can't run Billiards at work. It might therefore not work as
advertised and probably won't as I haven't done anything to Billiards
for a while. It should get you started nevertheless. I advise you to
look through Billiards' source as well. Most of it will probably not
make much sense but you should get a general idea of how it works and
it's not that much anyway. I'll try to implement my suggestions myself
when I make the changes I mentioned earlier but this might take a few
days. Give it a shot on your own until then and let me know if you
need further clarifications, explanations, help or whatever.
Dimitris
2010/1/11 Tadej Janež
<address@hidden>
Hi!
I've come across your Billiards simulator on The Linux Game Tome,
installed it, played with it for a while and I really like it so far.
Now on to the thing I would like to achieve with Billiards.
Firstly, I would like to specify a particular initial setting:
Table with pockets, white ball at position (x_w, y_w), black ball at
position (x_b, y_b) and no other balls.
Secondly, I would like to try many different shots, i.e. set different
parameters for Sidespin, Follow, Elevation and "Shot Force". However,
instead of using the graphical interface, I would like to specify these
parameters programmatically.
Thirdly, I would like to log/capture the final coordinates of both white
and the black ball.
All in all, I would like to write a script, which would simulate many
different shots from the given initial position and log the results to a
file.
If none of the above makes sense, please say it and I'll try to explain
it better.
Can you get me some tips to get started?
Thanks,
Tadej
--
Tadej Janež <address@hidden>
Fakulteta za računalništvo in informatiko
- [Billiards-devel] Programming experiments with Billiards, Tadej Janež, 2010/01/11
- Re: [Billiards-devel] Programming experiments with Billiards,
Dimitris Papavasiliou <=
- Message not available
- Message not available
- Re: [Billiards-devel] Programming experiments with Billiards, Dimitris Papavasiliou, 2010/01/15
- Re: [Billiards-devel] Programming experiments with Billiards, Tadej Janež, 2010/01/19
- Re: [Billiards-devel] Programming experiments with Billiards, Dimitris Papavasiliou, 2010/01/19
- Re: [Billiards-devel] Programming experiments with Billiards, Tadej Janež, 2010/01/19
- Re: [Billiards-devel] Programming experiments with Billiards, Dimitris Papavasiliou, 2010/01/19
- Re: [Billiards-devel] Programming experiments with Billiards, Tadej Janež, 2010/01/20
- Re: [Billiards-devel] Programming experiments with Billiards, Dimitris Papavasiliou, 2010/01/21