Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Considerations for isnear code

0 views
Skip to first unread message

konijn_

unread,
Nov 17, 2009, 3:20:17 PM11/17/09
to
Greetings,

I got once more exposed to this type of code to determine whether
something is near :
if m(i).x+1=p.x and m(i).y+1=p.y or
m(i).x+1=p.x and m(i).y-1=p.y or
m(i).x-1=p.x and m(i).y+1=p.y or
m(i).x-1=p.x and m(i).y-1=p.y or
m(i).x+1=p.x and m(i).y=p.y Or
m(i).x-1=p.x and m(i).y=p.y Or
m(i).x=p.x and m(i).y-1=p.y Or
m(i).x=p.x and m(i).y+1=p.y then


with m(i) being a monster, p being a player.
If your language of choice has the absole value function,
please consider

if abs( m(i).x - p.x ) < 2 and abs( m(i).y - p.y ) < 2 then

I know it might boggle the reader for about 5 seconds, but then
forever afterwards the sanity of the reader will thank you for it.
There is about a 17% chance that I botched this one, by all means
point out a shorter or better or simply working example.

Thanks,
T.

Jeff Lait

unread,
Nov 17, 2009, 3:38:51 PM11/17/09
to
On Nov 17, 9:20 pm, konijn_ <kon...@gmail.com> wrote:
>
> If your language of choice has the absole value function,
> please consider
>
> if abs( m(i).x - p.x ) < 2 and abs( m(i).y - p.y ) < 2 then
>
> I know it might boggle the reader for about 5 seconds, but then
> forever afterwards the sanity of the reader will thank you for it.
> There is about a 17% chance that I botched this one, by all means
> point out a shorter or better or simply working example.

IMHO, better:

if max(abs(m(i).x-p.x), abs(m(i).y-p.y)) < 2 then

Much better:
if mydist(m(i), p) < 2 then

Ie, distance is too common a thing to keep retyping!
--
Jeff Lait
(POWDER: http://www.zincland.com/powder)

konijn_

unread,
Nov 17, 2009, 4:53:51 PM11/17/09
to
On Nov 17, 3:38 pm, Jeff Lait <torespondisfut...@hotmail.com> wrote:
> On Nov 17, 9:20 pm, konijn_ <kon...@gmail.com> wrote:
>
>
>
> > If your language of choice has the absole value function,
> > please consider
>
> > if abs( m(i).x - p.x ) < 2 and abs( m(i).y - p.y ) < 2 then
>
> > I know it might boggle the reader for about 5 seconds, but then
> > forever afterwards the sanity of the reader will thank you for it.
> > There is about a 17% chance that I botched this one, by all means
> > point out a shorter or better or simply working example.
>
> IMHO, better:
>
> if max(abs(m(i).x-p.x), abs(m(i).y-p.y)) < 2 then

yeah, I also though about
if abs((m(i).x-p.x))*(m(i).y-p.y)) < 2 then

>
> Much better:
> if mydist(m(i), p) < 2 then

With matching comment
//Look I am writing a next gen rl ;)

J�rgen Lerch

unread,
Nov 18, 2009, 1:13:59 AM11/18/09
to
Saluton!

On Tue, 17 Nov 2009 13:53:51 -0800 (PST), konijn_ wrote:
> yeah, I also though about
> if abs((m(i).x-p.x))*(m(i).y-p.y)) < 2 then

Wouldn't work:

.m.
...
...
.@.

m(i).y-p.y = �3, but m(i).x-p.x = 0; �3 * 0 = 0.

Ad Astra!
JuL

--
jyn...@gmx.de / Schl�rf macht die Zeit und dann ist
J�rgen ,,JuL'' Lerch / sie weg.

Martin Read

unread,
Nov 20, 2009, 3:14:57 PM11/20/09
to
konijn_ <kon...@gmail.com> wrote:
[about distance computation]

In Martin's Dungeon Bash Experimental (C++), the syntax is:

if (c1.distance(c2) < 2) { /* foo */ }

because life is too short to work on an increasingly large game where
Cartesian coordinates are not first-class objects.

(The ability to treat Cartesian coordinate tuples as first-class objects
subject to arithmetic operators is, in my view, the single most compelling
reason to say that anyone starting a new roguelike should work in basic
C++ instead of in C.)
--
\_\/_/ turbulence is certainty turbulence is friction between you and me
\ / every time we try to impose order we create chaos
\/ -- Killing Joke, "Mathematics of Chaos"

Gelatinous Mutant Coconut

unread,
Nov 20, 2009, 10:23:42 PM11/20/09
to
On Nov 20, 3:14 pm, Martin Read <mpr...@chiark.greenend.org.uk> wrote:
> In Martin's Dungeon Bash Experimental (C++), the syntax is:
>
> if (c1.distance(c2) < 2) { /* foo */ }
>
> (The ability to treat Cartesian coordinate tuples as first-class objects
> subject to arithmetic operators is, in my view, the single most compelling
> reason to say that anyone starting a new roguelike should work in basic
> C++ instead of in C.)

The same behavior in plain old C is just as readable:

if (distance(c1, c2) < 2) { /* foo */ }

As far as coordinate arithmetic operators: How do you use those? I
could see them used if you are using the same (x,y) tuple type for
both coordinates and coordinate-transforms, (like 2D vectors in
Cartesian math, and is done in frameworks like OpenGL), but my
preference would probably be to have separate coordinate and offset
types for the purpose of type-checking, since I think 99% of the time
you won't want to add the global coordinate positions of two monsters.
Most of the time you want an offset between two coordinates, or the
coordinate offset by (x,y) from another coordinate.

(For the record, I'm not arguing against a carefully chosen subset of C
++ in place of C; I wouldn't want to bother with distingishing between
coordinate types and offset types without some form of easy
polymorphism.)

Jeff Lait

unread,
Nov 21, 2009, 2:39:56 PM11/21/09
to
On Nov 21, 4:23 am, Gelatinous Mutant Coconut

<gelatinousmutantcoco...@gmail.com> wrote:
> On Nov 20, 3:14 pm, Martin Read <mpr...@chiark.greenend.org.uk> wrote:
>
> > In Martin's Dungeon Bash Experimental (C++), the syntax is:
>
> > if (c1.distance(c2) < 2) { /* foo */ }
>
> > (The ability to treat Cartesian coordinate tuples as first-class objects
> > subject to arithmetic operators is, in my view, the single most compelling
> > reason to say that anyone starting a new roguelike should work in basic
> > C++ instead of in C.)
>
> The same behavior in plain old C is just as readable:
>
> if (distance(c1, c2) < 2) { /* foo */ }

Well, but that doesn't affect the fact that
if ((c1-c2).length() < 2)

can't be written nicely in C.

The overloading of +/- is what makes it really nice. And if you
overload *, it is COMPONENT WISE MULTIPLICATION. It is not cross
product. Do not make that mistake!

> As far as coordinate arithmetic operators: How do you use those? I
> could see them used if you are using the same (x,y) tuple type for
> both coordinates and coordinate-transforms, (like 2D vectors in
> Cartesian math, and is done in frameworks like OpenGL), but my
> preference would probably be to have separate coordinate and offset
> types for the purpose of type-checking, since I think 99% of the time
> you won't want to add the global coordinate positions of two monsters.
> Most of the time you want an offset between two coordinates, or the
> coordinate offset by (x,y) from another coordinate.

Can't you do something like this?

Vector operator+(const Vector, const Vector)
Point operator+(const Point, const Vector)
Point operator+(const Vector, const Point)

Anyways, I like this in principle. I even set it up in my Haskel
raytracer. But I'd be very worried about doing it in C++. The 99% is
the kill joy, I'd fear... Not to mention that when you have a nice
tuple, you'll want to abuse it - what about colours?

Gelatinous Mutant Coconut

unread,
Nov 22, 2009, 3:45:59 AM11/22/09
to
On Nov 21, 2:39 pm, Jeff Lait <torespondisfut...@hotmail.com> wrote:
> Anyways, I like this in principle.  I even set it up in my Haskel
> raytracer.  But I'd be very worried about doing it in C++.  The 99% is
> the kill joy, I'd fear...  Not to mention that when you have a nice
> tuple, you'll want to abuse it - what about colours?

I'm not sure if I follow your last point: What about colours?

Radomir Dopieralski

unread,
Nov 22, 2009, 2:22:06 PM11/22/09
to
At Sat, 21 Nov 2009 11:39:56 -0800 (PST), Jeff Lait wrote:

> On Nov 21, 4:23 am, Gelatinous Mutant Coconut
> <gelatinousmutantcoco...@gmail.com> wrote:
>> On Nov 20, 3:14 pm, Martin Read <mpr...@chiark.greenend.org.uk> wrote:
>>
>> > In Martin's Dungeon Bash Experimental (C++), the syntax is:
>>
>> > if (c1.distance(c2) < 2) { /* foo */ }
>>
>> > (The ability to treat Cartesian coordinate tuples as first-class objects
>> > subject to arithmetic operators is, in my view, the single most compelling
>> > reason to say that anyone starting a new roguelike should work in basic
>> > C++ instead of in C.)
>>
>> The same behavior in plain old C is just as readable:
>>
>> if (distance(c1, c2) < 2) { /* foo */ }
>
> Well, but that doesn't affect the fact that
> if ((c1-c2).length() < 2)
>
> can't be written nicely in C.

I don't know, maybe I have a strange taste, but the C version looks much
better to my eyes than the above. It even reads like a plain English
sentence, you see.

--
Radomir Dopieralski, http://sheep.art.pl

Luchino alias Samel

unread,
Nov 22, 2009, 2:46:28 PM11/22/09
to

[Class getDistanceFromPoint:c1 toPoint:c2];

Obj-c rulez 8p I like the way you can write in this exotic language.

--
-- Luca Giacometti alias Samel

Ray

unread,
Nov 23, 2009, 1:09:52 AM11/23/09
to
Radomir Dopieralski wrote:
> At Sat, 21 Nov 2009 11:39:56 -0800 (PST), Jeff Lait wrote:
>> On Nov 21, 4:23 am, Gelatinous Mutant Coconut wrote:
>>> if (distance(c1, c2) < 2) { /* foo */ }

>> Well, but that doesn't affect the fact that
>> if ((c1-c2).length() < 2)

>> can't be written nicely in C.

> I don't know, maybe I have a strange taste, but the C version looks much
> better to my eyes than the above. It even reads like a plain English
> sentence, you see.

Um, me too. I almost posted that same opinion yesterday in fact. I
think "distance" is a concept in its own right, and not an aspect
or property of a point. So 'distance(c1, c2)' definitely matches
the way I think of it better than 'c1.distance(c2)' or the overloaded
(c1-c2).length() you've written above.

It took me some time to realize what that last one even meant; you're
redefining subtraction on points to return a distance interval, and then
you're using a type field accessor defined on distance intervals to read
its length. And this is supposed to be simpler or clearer than
distance(c1,c2)? Excuse me, but that idea makes me giggle. Just the
fact that someone considers it clearer or simpler comes back to me every
so often for the last day or so and makes me laugh.

Bear


Jeff Lait

unread,
Nov 23, 2009, 3:50:05 AM11/23/09
to
On Nov 23, 7:09 am, Ray <b...@sonic.net> wrote:
> Radomir Dopieralski wrote:
> > At Sat, 21 Nov 2009 11:39:56 -0800 (PST), Jeff Lait wrote:
> >> On Nov 21, 4:23 am, Gelatinous Mutant Coconut wrote:
> >>> if (distance(c1, c2) < 2) { /* foo */ }
> >> Well, but that doesn't affect the fact that
> >> if ((c1-c2).length() < 2)
> >> can't be written nicely in C.
> > I don't know, maybe I have a strange taste, but the C version looks much
> > better to my eyes than the above. It even reads like a plain English
> > sentence, you see.
>
> Um, me too.  I almost posted that same opinion yesterday in fact.  I
> think "distance" is a concept in its own right, and not an aspect
> or property of a point.  So 'distance(c1, c2)' definitely matches
> the way I think of it better than 'c1.distance(c2)'

Agreed. But...

> or the overloaded
> (c1-c2).length() you've written above.  

is a lot easier to translate formulas into.

> It took me some time to realize what that last one even meant; you're
> redefining subtraction on points to return a distance interval, and then
> you're using a type field accessor defined on distance intervals to read
> its length.

No, that is not what it does.

"points" and "vectors" are being conflated here (but the above idiom
would have worked even if they were the same)

c1-c2 returns a tuple by doing coordinate wise subtraction. length()
is defined on tuples and does sqrt(x^2+y^2).

>  And this is supposed to be simpler or clearer than
> distance(c1,c2)?

I was not suggesting it was simpler, I was just trying to give an
example of where - operators make stuff easier. My imagination is
failing me, but I know from experience it is very liberating to be a
be able to add and subtract vectors and perform computation on the
reuslts without needing to generate a slew of tmeporary varaibles.

Like, for example:
dot(a-b, v)*v+b

Is my quick attempt at projecting a onto the line starting at b in
direction v. Of course you then write a project() function,
correcting whatever error I wrote above, but the point I think stands
that it makes for a cleaner code.

As for colours, when you have an arithmetic triple it is very useful
to use it for RGB values. It is quite often you want to blend,
darken, etc, such things in the same way one manipulates points. And
then the whole "vector vs point" distinction falls apart. Colours are
logically points, but it also makes sense to multiply colours by a
scalar to brighten, which doesn't make sense for points.

David Ploog

unread,
Nov 23, 2009, 4:02:49 AM11/23/09
to
On Mon, 23 Nov 2009, Jeff Lait wrote:
> On Nov 23, 7:09�am, Ray <b...@sonic.net> wrote:

>>>>> if (distance(c1, c2) < 2) { /* foo */ }

vs

>>>> if ((c1-c2).length() < 2)

>> I almost posted that same opinion yesterday in fact. �I think
>> "distance" is a concept in its own right, and not an aspect or property
>> of a point.
>

> "points" and "vectors" are being conflated here (but the above idiom
> would have worked even if they were the same)
>
> c1-c2 returns a tuple by doing coordinate wise subtraction. length()
> is defined on tuples and does sqrt(x^2+y^2).

This is a good point:

d(c1,c2) is the concept of metric (distance between vectors)
l(c1-c2) is the concept of norm (length of difference of vectors)

Both of them are completely conceptual. I only find the notation
(c1-c2).length() to be a bit odd, but that is just a matter of experience,
I guess.

David

Krice

unread,
Nov 23, 2009, 4:22:15 AM11/23/09
to
On 23 marras, 08:09, Ray <b...@sonic.net> wrote:
> So 'distance(c1, c2)' definitely matches
> the way I think of it better than 'c1.distance(c2)'

If member function notation is something you know then
c1.distance(c2) doesn't look odd. Although I think it
would be better to rename it c1.get_distance_to(c2).

Konstantin Stupnik

unread,
Nov 23, 2009, 5:09:21 AM11/23/09
to
Jeff Lait wrote:

> Well, but that doesn't affect the fact that
> if ((c1-c2).length() < 2)

while it is possible and will work in my case, I still prefer:
if(c1.distanceTo(c2) <2 )

but I use (c1-c2) too. Mostly like this:
direction=(dst-src).normalize();

But since integer diagonal distance is definitely <2,
and in some cases by "is near" you mean "immediately adjacent",
I have utility method for objects:
if(obj1.adjacentTo(obj2))

but in my case all objects do know their positions.

Stephan Houben

unread,
Nov 23, 2009, 7:01:52 AM11/23/09
to
David Ploog wrote:

> This is a good point:

Or a good vector? ;-)

>
> d(c1,c2) is the concept of metric (distance between vectors)

I think you mean "point" here.

> l(c1-c2) is the concept of norm (length of difference of vectors)
>
> Both of them are completely conceptual. I only find the notation
> (c1-c2).length() to be a bit odd, but that is just a matter of
> experience, I guess.

For that reason I would slightly prefer d(c1,c2) since it
is somewhat more abstract.
Not every metric space is a normed vector space.

If you arrange your tiles in an arbitrarily connected graph structure
(perhaps in order to produce NonEuclidianGeometryRL),
you would have d(c1, c2) but l(c1-c2) would not be clearly defined.

Stephan

Gelatinous Mutant Coconut

unread,
Nov 23, 2009, 11:19:54 AM11/23/09
to
On Nov 23, 7:01 am, Stephan Houben <steph...@planet.nl> wrote:
> For that reason I would slightly prefer d(c1,c2) since it
> is somewhat more abstract.
> Not every metric space is a normed vector space.

In fact, in roguelikes you probably do want several distinct distance
functions: In addition to the Euclidian metric, it's nice to have the
King's Move metric and the Taxi Cab metric. And whatever movement
penalty metric you use for pathfinding.

J�rgen Lerch

unread,
Nov 24, 2009, 3:35:50 AM11/24/09
to
Saluton!

On Sat, 21 Nov 2009 11:39:56 -0800 (PST), Jeff Lait wrote:
> Well, but that doesn't affect the fact that
> if ((c1-c2).length() < 2)
> can't be written nicely in C.

(I find length(c1-c2) more readable, too.)



> The overloading of +/- is what makes it really nice. And if you
> overload *, it is COMPONENT WISE MULTIPLICATION. It is not cross
> product. Do not make that mistake!

Uh? Why?
Probably there are occasions in Maths where you use a
component wise multiplication of vectors, but, uh, I
don't remember any. Usually you use multipliation with
a scalar value, the scalar multipliation of vectors,
and the cross product.

Ad Astra!
JuL

--
jy...@gmx.de / Never anger a dragon, for you will be
J�rgen ,,JuL'' Lerch / crunchy and taste good with ketchup

Jeff Lait

unread,
Nov 24, 2009, 12:26:30 PM11/24/09
to
On Nov 24, 9:35 am, "Jürgen Lerch" <jyn...@gmx.de> wrote:
>
> On Sat, 21 Nov 2009 11:39:56 -0800 (PST), Jeff Lait wrote:
> > The overloading of +/- is what makes it really nice.  And if you
> > overload *, it is COMPONENT WISE MULTIPLICATION.  It is not cross
> > product.  Do not make that mistake!
>
> Uh? Why?
> Probably there are occasions in Maths where you use a
> component wise multiplication of vectors, but, uh, I
> don't remember any. Usually you use multipliation with
> a scalar value, the scalar multipliation of vectors,
> and the cross product.

Cross product anti-generalizes. If you have (x,y) vectors, it is
really a scalar. If you have triples (x,y,z) you might think you are
happy until you add homogenous cooridinates (x,y,z,w) and decide
foolishly they should also use (x,y,z) cross product.

Component-wise is unsurprising, works with division, and works with
any length vector in the same manner. Yes, it is rare in geometry.
But then you reuse your hande triple (x,y,z) vector class for colours
and you are very happy you can just use a single * to modulate a
colour by a second colour.

More sensible than cross product is the dot product (which you note as
the first stage is a component wise multiplication...) or outer
product, both which generalize nicely but have the disatisfaction of
returning a different type than they take (vector dot vector = scalar,
vector outer vector = matrix)

Gelatinous Mutant Coconut

unread,
Nov 24, 2009, 7:17:09 PM11/24/09
to
On Nov 24, 12:26 pm, Jeff Lait <torespondisfut...@hotmail.com> wrote:
> Cross product anti-generalizes. If you have (x,y) vectors, it is
> really a scalar.  If you have triples (x,y,z) you might think you are
> happy until you add homogenous cooridinates (x,y,z,w) and decide
> foolishly they should also use (x,y,z) cross product.
>
> Component-wise is unsurprising, works with division, and works with
> any length vector in the same manner.  Yes, it is rare in geometry.
> But then you reuse your hande triple (x,y,z) vector class for colours
> and you are very happy you can just use a single * to modulate a
> colour by a second colour.
>
> More sensible than cross product is the dot product (which you note as
> the first stage is a component wise multiplication...) or outer
> product, both which generalize nicely but have the disatisfaction of
> returning a different type than they take (vector dot vector = scalar,
> vector outer vector = matrix)

I feel like the lack of a shared 'obvious' multiplication operator
across use cases is a strong argument in favor of not conflating
positionVector, offsetVector and colorVector as a single 'vector'
type.

Maybe you could have an abstractVector class that implements dot
product, cross product, and component-wise product, and then have the
specific vector types define their multiplication operator according
to what is sensible?

Kenneth 'Bessarion' Boyd

unread,
Nov 25, 2009, 10:28:26 AM11/25/09
to
On Nov 24, 11:26 am, Jeff Lait <torespondisfut...@hotmail.com> wrote:
> On Nov 24, 9:35 am, "Jürgen Lerch" <jyn...@gmx.de> wrote:
>
>
>
> > On Sat, 21 Nov 2009 11:39:56 -0800 (PST), Jeff Lait wrote:
> > > The overloading of +/- is what makes it really nice.  And if you
> > > overload *, it is COMPONENT WISE MULTIPLICATION.  It is not cross
> > > product.  Do not make that mistake!
>
> > Uh? Why?
> > Probably there are occasions in Maths where you use a
> > component wise multiplication of vectors, but, uh, I
> > don't remember any. Usually you use multipliation with
> > a scalar value, the scalar multipliation of vectors,
> > and the cross product.
>
> Cross product anti-generalizes. If you have (x,y) vectors, it is
> really a scalar.  If you have triples (x,y,z) you might think you are
> happy until you add homogenous cooridinates (x,y,z,w) and decide
> foolishly they should also use (x,y,z) cross product.

The situation is even worse in higher mathematics. The general way of
defining cross product to work with n-dimensional vectors:
* does not play well with homogeneous coordinates. (Unsurprisingly, as
they're really a way to represent a projective space of dimensionality
one lower than the vector.)
** Fine...define a wrapper homogenous coordinate class and rewrite
every single operation.
* The resulting vector dimension is not linear in the dimension of the
vector n; it's actually the (n-1)'th triangular number n(n-1)/2. It's
a really useful coincidence that the cross-product of two three-
dimensional vectors is a three-dimensional vector
** Not a big deal, just have to remember to fix up the outgoing
dimension properly.

> Component-wise is unsurprising, works with division, and works with
> any length vector in the same manner.  Yes, it is rare in geometry.
> But then you reuse your hande triple (x,y,z) vector class for colours
> and you are very happy you can just use a single * to modulate a
> colour by a second colour.

I'm a bit rusty there, but I'm pretty sure I'd want to modulate colors
only by transparency and reflection. Component-wise product only
shows up as a fluky special case.

> More sensible than cross product is the dot product (which you note as
> the first stage is a component wise multiplication...) or outer
> product, both which generalize nicely but have the disatisfaction of
> returning a different type than they take (vector dot vector = scalar,
> vector outer vector = matrix)

Yes...neither choice is overwhelmingly canonical, which is a strong
hint neither is a good design choice for operator* .

Pender

unread,
Nov 25, 2009, 11:37:45 AM11/25/09
to
On Nov 25, 10:28 am, "Kenneth 'Bessarion' Boyd" <zaim...@zaimoni.com>
wrote:

> I'm a bit rusty there, but I'm pretty sure I'd want to modulate colors
> only by transparency and reflection.  Component-wise product only
> shows up as a fluky special case.

Setting aside the general debate about procedural versus object-
oriented and the specifics of the object architecture, I can say that
I find myself multiplying colors toghether in my roguelike all the
time. If you have a tuft of green-blue grass in an area lit by a
yellow-white light and a bluish light, you get the display color by
multiplying the sum of the light colors with the object color. If you
have a scroll of magic mapping that displays the undiscovered portions
of the yellow with a purple hue, you multiply the inherent color of an
undiscovered square by a light purple color. If squares that the
player can remember but cannot currently see should have a blueish
"memory" cast to differentiate from dimly-lit cells in the line of
sight, you multiply by the blueish memory color.

Personally, I found it plenty intuitive to implement common color
manipulations as C functions, as in colorAverage(color1, color2,
weight), desaturate(color, weight), colorMultiply(color1, color2) or
colorAugment(color1, color2), but I don't want to say that this is
necessarily easier or harder than some sort of generalized C++
arithmetic suite for n-dimensional vectors since I've never tried the
latter. I'll leave that debate to the professional coders :)

Gerry Quinn

unread,
Nov 25, 2009, 2:16:13 PM11/25/09
to
In article <d179fc39-b9a9-452d-99cf-
b41660...@s15g2000yqs.googlegroups.com>, pende...@gmail.com
says...

> On Nov 25, 10:28 am, "Kenneth 'Bessarion' Boyd" <zaim...@zaimoni.com>
> wrote:
>
> > I'm a bit rusty there, but I'm pretty sure I'd want to modulate colors
> > only by transparency and reflection.  Component-wise product only
> > shows up as a fluky special case.
>
> Setting aside the general debate about procedural versus object-
> oriented and the specifics of the object architecture, I can say that
> I find myself multiplying colors toghether in my roguelike all the
> time. If you have a tuft of green-blue grass in an area lit by a
> yellow-white light and a bluish light, you get the display color by
> multiplying the sum of the light colors with the object color. If you
> have a scroll of magic mapping that displays the undiscovered portions
> of the yellow with a purple hue, you multiply the inherent color of an
> undiscovered square by a light purple color. If squares that the
> player can remember but cannot currently see should have a blueish
> "memory" cast to differentiate from dimly-lit cells in the line of
> sight, you multiply by the blueish memory color.

No you don't... what you are doing is much closer to averaging the
colours, which is essentially a form of addition.

- Gerry Quinn


Pender

unread,
Nov 25, 2009, 3:48:25 PM11/25/09
to
On Nov 25, 2:16 pm, Gerry Quinn <ger...@indigo.ie> wrote:

> No you don't... what you are doing is much closer to averaging the
> colours, which is essentially a form of addition.

I'm somewhat perplexed by this response. I would know, since I wrote
the code. I'm not even sure what it means to say that something is
"closer to" averaging than multiplying, but regardless, component-wise
multiplication is *exactly* what I am doing.

That is how light actually works. The perceived color of an object is
the component-wise PRODUCT of the object's pigment color and the (sum
of the) light color(s). If you have a pure red object under a pure
blue light, the object appears black. Adding or averaging the colors
does not achieve that effect no matter what coefficients or weights
you use.

Gerry Quinn

unread,
Nov 26, 2009, 7:08:17 AM11/26/09
to
In article <176e9d5f-387a-4c1e-8536-
95f118...@u7g2000yqm.googlegroups.com>, pende...@gmail.com
says...

But who uses pigment colours in computer graphics? We construct
colours from three light components.

You gave the following example:

"If squares that the
player can remember but cannot currently see should have a blueish
"memory" cast to differentiate from dimly-lit cells in the line of
sight, you multiply by the blueish memory color."

Let's say the square is yellow; RGB of ( 1.0, 1.0, 0.0 )

Your blueish memory indicator is, say: RGB of ( 0.75, 0.75, 1.0 )

How do you get the final colour? Multiplication of blue components
will always give zero.

Averaging, by contrast, will shift the square closer to the memory
colour, and always add some blue unless it is already saturated.

- Gerry Quinn


Pender

unread,
Nov 26, 2009, 1:49:48 PM11/26/09
to
On Nov 26, 7:08 am, Gerry Quinn <ger...@indigo.ie> wrote:

> But who uses pigment colours in computer graphics?  We construct
> colours from three light components.

If you have colored objects in your game that are lit by colored
lights, then you are simulating an interaction between pigment colors
and light colors, and multiplication is the way to do it. The three
light components are the means of displaying the result of your
simulation on the monitor.

> You gave the following example:
> "If squares that the
> player can remember but cannot currently see should have a blueish
> "memory" cast to differentiate from dimly-lit cells in the line of
> sight, you multiply by the blueish memory color."

I think it works fine: http://img21.imageshack.us/img21/8329/broguescreenshot.jpg

Yeah, maybe occasional cells have no blue component so they only get
dimmed, but the global effect looks consistent and achieves the
desired result.

Jotaf

unread,
Nov 26, 2009, 4:32:20 PM11/26/09
to
On Nov 26, 6:49 pm, Pender <penderpr...@gmail.com> wrote:
> Yeah, maybe occasional cells have no blue component so they only get
> dimmed, but the global effect looks consistent and achieves the
> desired result.

I implement lighting by multiplying the lights' colors. I also work
with computer vision in my day work and this is the most widely used
model (for Lambertian surfaces); arguing for averaging of colors as a
better model is nonsensical. However, the weird behavior when
components are missing is a valid concern and you can hack your way
around it by simply not using those kinds of colors in your game.

So in terms of implementation, you *never* want to have a color light
like (1,0,0), it has to have a minimum of every color (hence the
suggestion of "bright" colors a few posts back). (1,0.1,0.1) would be
better. Also in my game I add a little of each component to the end
result -- like adding a tenth of the value of each component -- it's
another little trick that makes sure extreme cases like red objects
appearing as black on a blue light don't occur.

Jotaf

Kenneth 'Bessarion' Boyd

unread,
Nov 26, 2009, 6:07:21 PM11/26/09
to
On Nov 25, 1:16 pm, Gerry Quinn <ger...@indigo.ie> wrote:
> In article <d179fc39-b9a9-452d-99cf-
> b4166015a...@s15g2000yqs.googlegroups.com>, penderpr...@gmail.com

All of transparency, reflection, and absorption can be viewed as
component-wise multiplicative, after proper scaling.

Arithmetic-averaging colors is not something you do physically when
emulating lighting. I'd consider arithmetic averaging followed by
normalizing intensity, only when changing the color basis. (say I want
to construct an image for someone who has normal vision, that
replicates what a red-green color-blind person sees; *then* I need to
rotate hues around to map the "correct" red and green reference hues
to (255,0,0) and (0,255,0) in [0,255]x[0,255]x[0,255] RGB
coordinates.)

Gelatinous Mutant Coconut

unread,
Nov 26, 2009, 7:42:03 PM11/26/09
to
As long as we're talking about colors, I've always wondered if it
would be possible to run the simulation using wavelengths, intensities
and the formula behind the color space cromaticity diagram (http://
commons.wikimedia.org/wiki/File:CIExy1931.png). It might end up too
complex, I'm not sure.

Gerry Quinn

unread,
Nov 27, 2009, 7:36:09 AM11/27/09
to
In article <57bb7d3f-c3b8-41a6-a374-bf1d8d9aef71
@g1g2000vbr.googlegroups.com>, pende...@gmail.com says...

I agree it looks fine; I wonder how much that is to do with your choice
of colour scheme, though. If you used a lot of saturated colours I
think you might have problems.

In my game I darken unseen squares, which is effectively scalar
multiplication.

I still find it hard to believe that vector multiplication is going to
be commonplace in most graphical designs.

- Gerry Quinn



Gerry Quinn

unread,
Nov 27, 2009, 7:42:34 AM11/27/09
to
In article <a31f1628-6154-45f7-b7f3-cf69fff729b2
@v30g2000yqm.googlegroups.com>, jot...@hotmail.com says...

Sounds like you find the need for at least *some* averaging!

I guess the issue is not very simple and maybe complex solutions are
required to get ideal results. After all, the red, green and blue dots
on our screens work quite well, but they do not correspond perfectly to
human vision, so it would be surprising if a perfect result could be
obtained from simple mathematical manipulations.

- Gerry Quinn


Joshua Day

unread,
Nov 29, 2009, 1:55:12 AM11/29/09
to
Pender <pende...@gmail.com> wrote:
> [...] If you have a tuft of green-blue grass in an area lit by a

> yellow-white light and a bluish light, you get the display color by
> multiplying the sum of the light colors with the object color. If you
> have a scroll of magic mapping that displays the undiscovered portions
> of the yellow with a purple hue, you multiply the inherent color of an
> undiscovered square by a light purple color. If squares that the
> player can remember but cannot currently see should have a blueish
> "memory" cast to differentiate from dimly-lit cells in the line of
> sight, you multiply by the blueish memory color.

Multiplication gives you the effect of lighting, it is true: and all of
the discussion on lighting -- in particular, never descending right to
0.0 and often surpassing 1.0, only to clip right before rendering -- is
right on target; but you do not seem to want a lighting effect. "A
bluish 'memory' cast" sounds to me of distant mountains, and Gerry Quinn
is right on track suggesting averages.

Blue light scatters in the atmosphere. A distant mountain's color is
the sum of its proper color (its color in a vacuum, say) and the color
of the intervening column of air. Likewise for fog, which scatters all
colors. Anything seen through it takes the sum of its proper color
(dimmed for distance and diffraction) and the color of the intervening
column of fog.

If you would evoke the dimness of memory or suspicion, then you want to
dim the cell and add the color of a mist. A mist has two components
then: a triple for dimming and a triple for glow. Multiply the cell's
color by the dimming triple (like you do now) and add the glow. Gerry's
suggested average obtains in the special case where the dimming is (0.5,
0.5, 0.5).

For magic you might consider less natural transformations, from negative
lighting (light components less than zero cast bright shadows) to
fluorescence (add some part of blue light to green and some part of
green to red, shifting light from more to less energetic). Milton
describes the flames of hell as casting darkness. Many minerals are
naturally fluorescent.

--
Joshua

0 new messages