This post is the 3rd in the series of touching an image pixel accurately. The second one is too complicated, now I have kept it clear and simple.
The image to be touch is middle handled (this makes scaling easier) and the image both moves and is scaled real time.
Here’s the source code:
Import mojo2 Import opengl.gles20 Function Main() New MyApp End Class MyApp Extends App Const WIDTH:Float = 80 Const HEIGHT:Float = 80 Field canvas:Canvas Field gfxBG:Image Field gfxBall:Image Field BallData:DataBuffer Field scaleX:Float, scaleY:Float Field scale:Float Field touchX:Float, touchY:Float Field angle:Float Field x:Int, y:Int Field hit:Bool = False Method OnCreate() SetDeviceWindow(800,600,0) canvas = New Canvas scaleX = DeviceWidth() / 800.0 scaleY = DeviceHeight() / 600.0 gfxBG = Image.Load("bg.jpg",0,0) gfxBall = Image.Load("ball.png") ' By default this image is middle handled ("ball.png",.5,.5) ' Information of "ball.png" image is loaded here BallData = LoadImageData("cerberus://data/ball.png") ' If you're using Monkey X, change cerberus to monkey SetUpdateRate(30) End Method OnUpdate() Local coordX:Float, coordY:Float scale = 3 - Cos(angle * 4) ' calculate scaling factor to the image angle = angle + 2 x = 800 / 2 + Cos(angle) * 150 y = 600 / 2 + Sin(angle) * 150 If TouchDown(0) > 0 Then hit = False touchX = TouchX() touchY = TouchY() ' The image is middle handled ' Here we find the "virtual" (=scaled) top left corner coordX = x - (WIDTH / 2) * scale coordY = y - (HEIGHT / 2) * scale ' Is the object touched at its rectangle? If touchX - coordX < WIDTH * scale And touchX - coordX > 0 And touchY - coordY < HEIGHT * scale And touchY - coordY > 0 Then Local pointX:Int Local pointY:Int Local data:Int ' In the actual touch test we check the original image; ' that is why following "scaling" must be done for the touch point pointX = Int((touchX - coordX) / scale) pointY = Int((touchY - coordY) / scale) data = BallData.PeekInt(pointX * 4 + pointY * WIDTH * 4) & $FF000000 ' If alpha <> 0 there are pixels If data <> 0 Then hit = True Else hit = False Endif Endif End Method OnRender() canvas.PushMatrix() canvas.Scale(scaleX,scaleY) canvas.SetBlendMode(BlendMode.Alpha) canvas.DrawImage gfxBG,0,0 If hit = True Then canvas.SetBlendMode(BlendMode.Additive) Else canvas.SetBlendMode(BlendMode.Alpha) canvas.DrawImage(gfxBall, x, y, 0, scale, scale) canvas.Flush canvas.PopMatrix End End Class
The actual test is made for the original image data, that is left intact. Because the image is middle handled in order to get the top left corner of the image, one must decrease half of the width and height of the image from the x, y of the image. But as the image is scaled the actual graphical top left corner is x – (width / 2) * scale and y – (height / 2) * scale.
When then top left corner of the rectangle is calculated, to this is added the scaled size: width * scale and height * scale. This is taken care of in the if-sentence, when checking if in the rectangle is touched.
When one has the touching point, the point in the image must be “scaled” by the scale factor, see the commented part of the code for this.
In the actual test is tested is the picture’s alpha value in the calculated point <> 0; if it is, the image that has transparent pixels, must have been touched.
Clear and simple. 🙂
Below is a video of regarding this post:
If you want to compile this in Monkey X, just change in the LoadImageData-part “cerberus” to “monkey”.
In my Memorable Melodies game is used slightly different code to touch the images, because the images to be touched don’t have “holes”.