Hi folks,
I thought I'd post this in case anyone else finds the same problem .. :)
I was trying an example program to illustrate the 'GetKeyState' command for an upcoming addition to my user guide series.
So I wrote this little Maze program, and found I needed to know when the marker collided with the walls of the maze.
Rather than try to use x,y co-ordinates for this, I decided to detect when the colour of the walls was found in a 'GetPixel' command.
To my surprise, the marker just went straight through the walls ..
I found after a bit of research, that the GetPixel command works in Blue, Green, Red values - not Red, Green, Blue.
You can prove this by using GetPixel on a known colour area, and calculating:
col = GETPIXEL(w, x, y )
red = (col & 0x0000ff)
green = (col & 0x00ff00) / 256
blue = (col & 0xff0000) / 65536
You will find the r,g,b components are reversed.
Once that little snag was overcome by testing for the reverse colour, the program then turned out as follows ..
' GWS Feb 2010
' Creative Basic Code
' (use the arrow keys to move the marker)
def w:window
def TicksPerSecond,run:int
def sw,sh,gametime,mwid,nmaze:int
def posy,mcol,rcol,scol:int
def markspeed:float
def markx,marky,dt,ts:float
def a$:string
declare "kernel32",GetTickCount(),int
type maze
def x:int
def y:int
def wid:int
def hgt:int
endtype
def m[110]:maze
autodefine "off"
sw = 1024 :' screen width
sh = 768 :' screen height
window w,0,0,sw,sh,@NOAUTODRAW|@MINBOX|@MAXBOX|@SIZE,0,"Maze",mainwindow
centerwindow w
' define a Button control ..
control w, "B,Exit, (1024 - 70)/2, 650, 70, 30, @ctlbtnflat, 1"
setcontrolcolor w, 1, 0, rgb(120,140,220)
' create a DX screen ..
if CREATESCREEN(w,sw,sh) < 0
messagebox w, "Could not create DirectX screen","Error"
closewindow w
end
endif
' game timing ..
TicksPerSecond = 40 :' number of frames per second
ts = 1.0 / TicksPerSecond :' game frame interval (sec)
dt = 1000.0 * ts :' game update interval (msec)
drawmode w,@TRANSPARENT
launch
run = 1
waituntil run = 0
stoptimer w
closewindow w
END
mainwindow:
select @CLASS
case @IDCLOSEWINDOW
run = 0
case @IDKEYDOWN
if (@code = 0x1B) then run = 0 :' Escape key ends game
case @IDCONTROL
if (@controlid = 1) then run = 0
case @IDDXUPDATE
dxfill w,rgb(20,100,200)
' display main text ..
setfont w, "Arial", 20, 700, @sfitalic
frontpen w,RGB(180,180,250)
move w, 350,20
print w, "Navigate out of the Maze"
' draw the maze ..
' horizontal lines ..
for i = 1 to 52
rect w,m[i].x,m[i].y,m[i].wid,m[i].hgt,mcol,mcol
next i
' vertical lines ..
for i = 60 to 109
rect w,m[i].x,m[i].y,m[i].wid,m[i].hgt,mcol,mcol
next i
' temporary design grid lines ..
'for i = 1 to 18
' line w,100,100 + (i-1)*30,920,100+(i-1)*30,rgb(0,180,180)
'next i
'for i = 1 to 30
' line w,120+(i-1)*27,80,120+(i-1)*27,640,rgb(0,180,180)
'next i
' update the game status ..
update
DXFLIP w
endselect
RETURN
sub update
' update game status every 'dt' msec ..
if (GetTickCount() - gametime > dt)
' check for collision with the maze walls ..
' look 5 px ahead, allowing for the marker size of 10 px ..
' Note: The GetPixel function works in 'b,g,r' format, so test for the reversed colours in 'rcol'
' which are the reverse of the actual 'r,g,b' colour.
if getkeystate(0x27) :' move right
if (GETPIXEL(w, markx + 15, marky) <> rcol) & (GETPIXEL(w, markx + 15, marky + 10) <> rcol)
if (markx < (sw - 25)) then markx = markx + markspeed * dt
endif
endif
if getkeystate(0x25) :' move left
if (GETPIXEL(w, markx - 5, marky) <> rcol) & (GETPIXEL(w, markx -5, marky + 10) <> rcol)
if (markx > 15) then markx = markx - markspeed * dt
endif
endif
if getkeystate(0x26) :' move Up
if (GETPIXEL(w, markx, marky - 5) <> rcol) & (GETPIXEL(w, markx + 10, marky - 5) <> rcol)
if (marky > 15) then marky = marky - markspeed * dt
endif
endif
if getkeystate(0x28) :' move down
if (GETPIXEL(w, markx, marky + 15) <> rcol) & (GETPIXEL(w, markx + 10, marky + 15) <> rcol)
if (marky < (sh - 25)) then marky = marky + markspeed * dt
endif
endif
rect w,markx,marky,10,10,rgb(20,200,20),rgb(20,200,20)
endif
return
sub launch
' routine to launch a new game ..
'set intial values
markx = 508 :' marker starting x position
marky = 365 :' marker starting y position
markspeed = 0.1 :' marker speed
' set maze parameters ..
nmaze = 90
mcol = rgb(50,50,80) :' maze wall colour in r,g,b format
' set a test pixel at x=0, y=0 to the maze colour.
pset w,0,0,mcol
' read it back to check user's colour settings in Windows (16,24 or 32 bit) ..
scol = getpixel(w,0,0)
' and use this as the reverse colour for GetPixel to check as being the wall colour.
rcol = scol
' horizontal walls ..
m[1].x = 120 : m[1].y = 100 : m[1].wid = 378
m[2].x = 525 : m[2].y = 100 : m[2].wid = 380
m[3].x = 148 : m[3].y = 130 : m[3].wid = 268
m[4].x = 445 : m[4].y = 130 : m[4].wid = 295
m[5].x = 768 : m[5].y = 130 : m[5].wid = 110
m[6].x = 175 : m[6].y = 160 : m[6].wid = 215
m[7].x = 445 : m[7].y = 160 : m[7].wid = 268
m[8].x = 795 : m[8].y = 160 : m[8].wid = 80
m[9].x = 255 : m[9].y = 190 : m[9].wid = 163
m[10].x = 473 : m[10].y = 190 : m[10].wid = 240
m[11].x = 823 : m[11].y = 190 : m[11].wid = 27
m[12].x = 283 : m[12].y = 220 : m[12].wid = 243
m[13].x = 580 : m[13].y = 220 : m[13].wid = 108
m[14].x = 795 : m[14].y = 220 : m[14].wid = 28
m[15].x = 310 : m[15].y = 250 : m[15].wid = 188
m[16].x = 553 : m[16].y = 250 : m[16].wid = 108
m[17].x = 770 : m[17].y = 250 : m[17].wid = 80
m[18].x = 120 : m[18].y = 280 : m[18].wid = 80
m[19].x = 284 : m[19].y = 280 : m[19].wid = 80
m[20].x = 418 : m[20].y = 280 : m[20].wid = 243
m[21].x = 768 : m[21].y = 280 : m[21].wid = 80
m[22].x = 148 : m[22].y = 310 : m[22].wid = 90
m[23].x = 312 : m[23].y = 310 : m[23].wid = 80
m[24].x = 446 : m[24].y = 310 : m[24].wid = 50
m[25].x = 525 : m[25].y = 310 : m[25].wid = 55
m[26].x = 795 : m[26].y = 310 : m[26].wid = 88
m[27].x = 174 : m[27].y = 340 : m[27].wid = 216
m[28].x = 472 : m[28].y = 340 : m[28].wid = 80
m[29].x = 765 : m[29].y = 340 : m[29].wid = 148
m[30].x = 202 : m[30].y = 370 : m[30].wid = 162
m[31].x = 660 : m[31].y = 370 : m[31].wid = 216
m[32].x = 175 : m[32].y = 400 : m[32].wid = 160
m[33].x = 467 : m[33].y = 400 : m[33].wid = 30
m[34].x = 528 : m[34].y = 400 : m[34].wid = 30
m[35].x = 688 : m[35].y = 400 : m[35].wid = 160
m[36].x = 202 : m[36].y = 430 : m[36].wid = 52
m[37].x = 310 : m[37].y = 430 : m[37].wid = 52
m[38].x = 440 : m[38].y = 430 : m[38].wid = 145
m[39].x = 418 : m[39].y = 460 : m[39].wid = 215
m[40].x = 392 : m[40].y = 490 : m[40].wid = 106
m[41].x = 553 : m[41].y = 490 : m[41].wid = 106
m[42].x = 335 : m[42].y = 520 : m[42].wid = 135
m[43].x = 528 : m[43].y = 520 : m[43].wid = 158
m[44].x = 768 : m[44].y = 520 : m[44].wid = 55
m[45].x = 173 : m[45].y = 550 : m[45].wid = 60
m[46].x = 310 : m[46].y = 550 : m[46].wid = 53
m[47].x = 418 : m[47].y = 550 : m[47].wid = 270
m[48].x = 768 : m[48].y = 550 : m[48].wid = 82
m[49].x = 148 : m[49].y = 580 : m[49].wid = 110
m[50].x = 310 : m[50].y = 580 : m[50].wid = 188
m[51].x = 525 : m[51].y = 580 : m[51].wid = 350
m[52].x = 125 : m[52].y = 610 : m[52].wid = 780
for i = 1 to 52
m[i].hgt = 10
next i
' vertical walls ..
m[60].x = 120 : m[60].y = 100 : m[60].hgt = 520
m[61].x = 903 : m[61].y = 100 : m[61].hgt = 520
m[62].x = 147 : m[62].y = 130 : m[62].hgt = 160
m[63].x = 174 : m[63].y = 160 : m[63].hgt = 120
m[64].x = 201 : m[64].y = 190 : m[64].hgt = 100
m[65].x = 228 : m[65].y = 160 : m[65].hgt = 150
m[66].x = 412 : m[66].y = 130 : m[66].hgt = 70
m[67].x = 255 : m[67].y = 190 : m[67].hgt = 130
m[68].x = 283 : m[68].y = 230 : m[68].hgt = 90
m[69].x = 385 : m[69].y = 260 : m[69].hgt = 60
m[70].x = 442 : m[70].y = 160 : m[70].hgt = 60
m[71].x = 520 : m[71].y = 220 : m[71].hgt = 60
m[72].x = 553 : m[72].y = 200 : m[72].hgt = 50
m[73].x = 683 : m[73].y = 220 : m[73].hgt = 122
m[74].x = 710 : m[74].y = 190 : m[74].hgt = 152
m[75].x = 736 : m[75].y = 130 : m[75].hgt = 248
m[76].x = 765 : m[76].y = 130 : m[76].hgt = 130
m[77].x = 793 : m[77].y = 160 : m[77].hgt = 70
m[78].x = 843 : m[78].y = 190 : m[78].hgt = 70
m[79].x = 873 : m[79].y = 160 : m[79].hgt = 150
m[80].x = 765 : m[80].y = 280 : m[80].hgt = 60
m[81].x = 467 : m[81].y = 340 : m[81].hgt = 60
m[82].x = 548 : m[82].y = 340 : m[82].hgt = 60
m[83].x = 440 : m[83].y = 310 : m[83].hgt = 120
m[84].x = 575 : m[84].y = 310 : m[84].hgt = 120
m[85].x = 147 : m[85].y = 310 : m[85].hgt = 275
m[86].x = 173 : m[86].y = 340 : m[86].hgt = 215
m[87].x = 198 : m[87].y = 430 : m[87].hgt = 95
m[88].x = 248 : m[88].y = 430 : m[88].hgt = 155
m[89].x = 223 : m[89].y = 460 : m[89].hgt = 95
m[90].x = 277 : m[90].y = 400 : m[90].hgt = 220
m[91].x = 307 : m[91].y = 430 : m[91].hgt = 130
m[92].x = 332 : m[92].y = 460 : m[92].hgt = 70
m[93].x = 385 : m[93].y = 520 : m[93].hgt = 70
m[94].x = 385 : m[94].y = 340 : m[94].hgt = 160
m[95].x = 493 : m[95].y = 490 : m[95].hgt = 60
m[96].x = 523 : m[96].y = 460 : m[96].hgt = 70
m[97].x = 358 : m[97].y = 370 : m[97].hgt = 130
m[98].x = 413 : m[98].y = 280 : m[98].hgt = 190
m[99].x = 602 : m[99].y = 280 : m[99].hgt = 160
m[100].x = 628 : m[100].y = 310 : m[100].hgt = 160
m[101].x = 655 : m[101].y = 280 : m[101].hgt = 220
m[102].x = 682 : m[102].y = 400 : m[102].hgt = 130
m[103].x = 710 : m[103].y = 430 : m[103].hgt = 160
m[104].x = 737 : m[104].y = 405 : m[104].hgt = 155
m[105].x = 763 : m[105].y = 430 : m[105].hgt = 100
m[106].x = 790 : m[106].y = 400 : m[106].hgt = 95
m[107].x = 817 : m[107].y = 430 : m[107].hgt = 100
m[108].x = 845 : m[108].y = 400 : m[108].hgt = 160
m[109].x = 873 : m[109].y = 370 : m[109].hgt = 220
for i = 60 to 109
m[i].wid = 10
next i
return
I'll include it in the user notes as well if I ever get them finished .. :)
Graham
(Edit: Program modified to cater for user's Windows colour settings ie. 16,24, or 32 bit colour)
Graham your Maze looks great but marker rectangle goes trough maze wals.
Hi Aurel,
Just a guess, but I think you may not be set for 32-bit colour for Windows - the GetPixel function only returns the correct r,g,b values at the highest setting. At lower settings, it chooses the nearest values it can - but they are unlikely to match.
That's one snag with using the colour detection method .. :)
Here's an old query from the Pyxia forum:
__________________________________
My Colors Are Wrong ...
Hi Guys and Gals,
I've been trying to read color values from the screen, and I'm not getting 'accurate' rendition .. :(
Here's a test program:
_________________
def w:WINDOW
def wstyle,key:int
def col,red,green,blue,textW,textH:int
def a$:string
autodefine "OFF"
wstyle = @SIZE|@MINBOX|@MAXBOX
WINDOW w,50,50,500,400,wstyle,0,"Colour Test",handler
CONTROL w,"B, Exit, 210, 300, 70, 35, 0, 1"
'****************************************************
' change the color values to check the RGB result ..
SETWINDOWCOLOR w,RGB(20,10,150)
col = GETPIXEL(w, 380 ,10 )
red = (col & 0x0000ff)
green = (col & 0x00ff00) / 256
blue = (col & 0xff0000) / 65536
a$ = "RGB(" + str$(red)+","+str$(green)+","+str$(blue)+")"
frontpen w, RGB(255,255,255)
SETFONT w, "Times New Roman",14,500
GETTEXTSIZE w, a$, textW, textH
move w,(500-textW)/2,100
PRINT w,a$
'***************************************************
WAITUNTIL w = 0
END
SUB handler
SELECT @CLASS
case @IDCLOSEWINDOW
CLOSEWINDOW w
case @IDCHAR
key = @CODE
if key = 27 then CLOSEWINDOW w
case @IDCONTROL
select @CONTROLID
case 1
CLOSEWINDOW w
endselect
ENDSELECT
RETURN
_________________
You will see that the pixel colors are not quite right .. can be 5 to 10% adrift .. Is this something other folk have noticed - a built in effect of pc graphics maybe ..
A bit more accurate would have been nice .. :)
Graham
_____________________________________________________
Graham,
Depends on your desktop settings. If you use a 16 or 24bit display then the colors are mapped to closest values by windows. The RGB statement specifies 32 bit color quantities 0-255. For a 16 bit screen this would get adjusted to 0-127 for each value.
When converting back Windows uses the reverse of the formula, which might be as simpe as dividing by 2 I suppose. It may be more complex than that as I remember something about color profiles for monitors and such.
Paul.
____________________________________________________
Paul,
Many thanks, you've hit the nail right on the head again as usual .. :)
I was running in 'High Color' 16 bit mode. If I change to 'Truecolor' 32 bit mode the results are exact.
That leaves me with an upcoming application which will work well in Truecolor, but not so well in High Color, depending on the user's settings - problems, problems ... :)
happy days,
Graham
____________________________________________
I hope that's the answer .. ;D
all the best, :)
Graham
Yes Graham you right i'm runing in 16bit mode always.
Ok i switch to 32bit and program work ;)
Yes this things looks problematic ::)
thats why i've learned its better to use arrays or alike to store data in as opposed to the actual window co-ords as you never know what depth the user has setup. on some graphics cards they can't support 32 bit .. only 24 bit tops ..
I used to code on an old C64 where the pixels were always stored in a colour map area and used to use peeks / pokes to read and set them. but when i upgraded (a matter of opinion) to a true computer I learned never to assume anything.. and stored the color and content data in arrays as opposed to off the screen.
What .. ? .. you mean I need to find another solution .. ;D
The colour one seemed so straightforward - until the snags pop up that is .. ::)
The only other approach that comes to mind is a cell matrix with data saying wall or non-wall.
Then the marker has to test where it is, top - left - down and up to see if it can move or not. Another tricky bit of logic needed methinks .. :)
Hey, this was only supposed to be a throwaway example of using GetKeystate .. :) Nothing's easy ..
That makes maze tracing a pretty tricky application - and my daughter would like a button that says 'Click me for another Maze' .. :o
Oh, yes - it took me ages to specify the layout of that one .. ;D An auto maze generator - yep, very interesting.
best wishes, :)
Graham
"The only other approach that comes to mind is a cell matrix with data saying wall or non-wall."
I remember coming across these programs with my pacman clone that I wrote. What I eventually ended up doing was rendering the maze as a sprite, and using sprite collision routines to determine if the user had run into the wall.
I have never used it personally (all the cool kids are doing it!) but you could play around with the GetNearestColor() API function in the GDI32.dll.
Hi ZD .. :)
Two great ideas .. thanks. I never thought of making a big sprite out of it .. ;D I'll have to try that.
I should think it would be less work than specifying all those rectangle x,y,wid,hgt details.
I'd not come across the GetNearestColor() API function - that could well solve the problem as well.
You're full of good ideas .. ;D ;D
best wishes, :)
Graham
Hi folks,
It was easier than I'd thought .. :)
Here's how:
' set a test pixel at x=0, y=0 to the maze colour.
pset w,0,0,mcol
' read it back to check user's colour settings in Windows (16, 24 or 32 bit) ..
scol = getpixel(w,0,0)
' and use this as the reverse colour for GetPixel to check as being the wall colour.
rcol = scol
Then, whatever colours the user's Windows settings are displaying, the readback will discover it, and use it to test the wall colour .. is that sneaky or what ? ::)
I've updated the program listing to incorporate the change ..
best wishes, :)
Graham
oh, very clever ;D
duh! :-[