ImageClicked

Blitz3D Forums/Blitz3D Programming/ImageClicked

AndyBoy_UK(Posted 2004) [#1]
Hi there everyone,

I have a little question for you all.

I am writing an editor for a game that involves a maze (nice simple array of walls or floors) and items being placed at points in the maze.

In the editor the items are represented by images that are drawn over the map.

The items are all stored in a type array that looks kind of like the following

type tyItem
field id%
field name$
field x%, y%, level%
field hndIconImage
end type

now the hndIconImage is the image handle of the item that is actually drawn on the map.

So the question is this.. Is there a way I can get which tyItem has been clicked on the map using some sort of rectcollide and check.

Im pretty sure it is going to be waaay too ugly to do it and I have plenty of ways around it if not, but I thought if someone has an idea on how to do this (with a command that I have missed or something) then I would be very grateful.

Ideally the code would look like

if mousehit(1) then
clickedItem.tyItem = itemClicked.tyItem(mouseX(), mouseY(), level%)
end if

function itemClicked.tyItem(x%, y%, level%)

if imageUnder(etc.etc.) or something like that ...

... This is the bit I need help with ...

end function



So over to the experts.


Bot Builder(Posted 2004) [#2]
Hmm, Weel luckily for you there is a command like this called camerapick. Basically, you just give it your cam, and the x/y of the mouse and it'll return the handle of the entity you hit. You also have to make sure to set the items to be pickable with the pickmode command. You can also set the terrain to be pickable as well so that you cant pick through walls. What you do if an item was picked is loop through your types checking if its the one that was picked. upon a match, you can do whatever you want and exit the loop. You could also use some special memory commands and do somthing like

if mousedown(1) then
p=camerapick(cam,mousex(),mousey())
if p then pi.tyitem=object.tyitem(peekF(ENTITY_RADIUSZ+p))
endif

This would be more efficient but harder to set up. I would go for:

if mousedown(1) then
p=camerapick(cam,mousex(),mousey())
for t.tyitem= each tyitem
if t\
next
endif

Gahhh!!!! This is 2d???? whys it in the 3d forum????

You can just loop through your types, and do a rectangle around the weopon.


AndyBoy_UK(Posted 2004) [#3]
Ahh, thats cool but I need it in 2d im afraid?


Ross C(Posted 2004) [#4]
Hey, how about....

function find_image()
  for t.type=each type
     if imagecollided(t\image_handle,t\x,t\y,0,pointer,mousex(),mousey(),0) then
         return t.type ; don't actually know what here, but you've found the type object you want
     end if
  next
end function


search thru all the types comparing the pointer image against the tile and returns the type object?? I dunno what to do once you've found the image :)

May i suggest you create a very small image (1x1) at the tip of the pointer and use that for imagecolliding. More accurate, and it's impossible to select two tiles at once :)


Neo Genesis10(Posted 2004) [#5]
Try the following:

Global left_click
Global right_click

; Add the following lines in your main loop
left_click = MouseHit(1)
right_click = MouseHit(2)

Function LeftClicked( image.tyitem )
	If not left_click Then Return False
	img = CreateImage(1,1)
	If ImagesOverlap(img, MouseX(), MouseY(), image\hndIconImage, image\x, image\y)
		FreeImage img
		Return True
	EndIf
End Function

Function RightClicked( image.tyitem )
	If not right_click Then Return False
	img = CreateImage(1,1)
	If ImagesOverlap(img, MouseX(), MouseY(), image\hndIconImage, image\x, image\y)
		FreeImage img
		Return True
	EndIf
End Function



AndyBoy_UK(Posted 2004) [#6]
@ Ross C: The pointer idea is pretty nifty, never would have thought to do that and would have used the rectcollide but I fear that searching through all the types and comparing it would be too slow for what I have in mind, there could be hundreds, even thousands of the item type in there at one time.

Its a shame there isnt a way to filter or narrow down type lists, like the only iterate the ones that are on tiles near the mouse but again you would have to go through the whole lot.

@ NeoGen: Your code is similar to what Ross was saying but you are suggesting that I loop through all the types and pass them to a function? Or have I misunderstood.

@ Bot Builder: I put it in here because I dont own Blitz+ but I do own B3d I have the commands in B3d available.

If the mod's want to move it, feel free and sorry if it was misleading.

Cheers for all the help so far.


Ross C(Posted 2004) [#7]
Well, speed it up by using imageoverlap. Cycling 1000 types for collisions isn't slow, honestly. I has my breakout game comparing 15 balls against 45 odd blocks.

That's about 635 odd checks. I was still getting a decent playable framerate. And if it's an editor, speed isn't of the essence :)


AndyBoy_UK(Posted 2004) [#8]
True, I suppose I can give it a go and see what sort of impact it has on speed. after all it is only when the mouse is clicked on the item.

Cheers for teh help, I will let you know how I get on.


Neo Genesis10(Posted 2004) [#9]
AndyBoy: Yes, my idea requires you to cycle through and pass to the function. The main reason for something like this is to get around the MouseHit problem. There are other ways to do this, but I like to break things down into bite-sized chunks.

Try to keep MouseHit to only one call per button per main loop that way the user wont need lightning fast reactions to select the right menu options. Its also tidier to use than MouseDown as it resets after each click.


AndyBoy_UK(Posted 2004) [#10]
Thanks for all your help, I will have a play around with these suggestions and repost here if it doesnt work. :)


Paul "Taiphoz"(Posted 2004) [#11]
OK its a tile systems.

So im gona guess that say each tile is 10*10.
All you have to do is loop through the tiles. and find the tile the mouse is over, no need for all this images or rect collision checking.

function get_item()
  local mx,my
  mx=mousex()/10
  my=mousey()/10
  for t.tyitem= each tyitem 
     if t\x=mx and t\y=my
       return t.tyitem
       exit
     end if
  next 
end function


The above code like the others will just return the handle to the item you want. You know the mouse X,Y so its easy to get the tile location the mouse is sitting over.

Above code might need a little tweaking .. oh yeah it should also be a lot faster tha the others ;)


AndyBoy_UK(Posted 2004) [#12]
It is a tile system, but the items that sit above arent always tile shaped. Some of them , even though are a part of a wall tile, hang off the side into a corridor tile (like a fountain), and the request for the editor was that if you clicked on the fountain (hanging over the corridor tile) it showed the items on the wall tile rather than the corridor items.

I think it would make a nice addition but If it is going to cause a major slow down then Im not sure it is worth it.

Cheers Yav, good to see ya again :)