Pixel Perfect Collisions (v63)

Monkey Forums/Monkey Code/Pixel Perfect Collisions (v63)

therevills(Posted 2012) [#1]
Does not support Scale or Rotation :(




Luis(Posted 2015) [#2]
How do I add images?


therevills(Posted 2015) [#3]
Just load the images as normal and assign it to the Sprite variable image, then draw it in CreateImages method.


Luis(Posted 2015) [#4]
Strict

Import mojo

Global bgr:Int = 0

Function Main:Int()
	New MyApp()
	Return 0
End

Class MyApp Extends App
	Field player:Sprite
	Field enemy:Sprite

	Method OnCreate:Int()
		SetUpdateRate(60)
		player = New Sprite
		enemy = New Sprite
		Return 0
	End
	
	Method OnUpdate:Int()
		If player.Collide(enemy) Then
			bgr = 255
		Else
			bgr = 0
		End
		Return 0
	End
	
	Method OnRender:Int()
		Cls(bgr, 0, 0)
		player.Draw(MouseX(), MouseY())
		enemy.Draw(400, 300)
		
		If player.collisionRect <> Null Then
			DrawText player.collisionRect.ToString(), 10, 10
		End
		Return 0
	End
End

Class Sprite
	Field image:Image
	Field monito:Image
	Field pixels:Int[]
	Field createImages:Bool
	Field x:Float, y:Float
	Field collisionRect:Rect
	
	Method New()
		monito = LoadImage("monkey.png")
		image = CreateImage(100, 160)
		pixels = New Int[image.Width() * image.Height()]
		createImages = True
	End
	
	Method Draw:Void(px:Float, py:Float)
		CreateImages()
		x = px
		y = py
		DrawImage(image, x, y)
		If collisionRect <> Null Then
			SetColor(255, 0, 255)
		'	DrawRect(collisionRect.x, collisionRect.y, collisionRect.width, collisionRect.height)
			SetColor(255, 255, 255)
		End
	End
	
	Method CreateImages:Void()
		If Not createImages Return
		createImages = False
		Cls(0, 0, 0)
		DrawImage(monito, 50, 50)
		ReadPixels(pixels, 0, 0, image.Width(), image.Height())
		
		' convert the mask colour (black) to alpha
		For Local i:Int = 0 Until image.Width() * image.Height()
			Local argb:Int = pixels[i]
			Local a:Int = (argb Shr 24) & $ff
			Local r:Int = (argb Shr 16) & $ff
			Local g:Int = (argb Shr 8) & $ff
			Local b:Int = argb & $ff

			If a = 255 And r = 0 And g = 0 And b = 0 Then
				a = 0
				argb = (a Shl 24) | (r Shl 16) | (g Shl 8) | b
				pixels[i] = argb
			End
		Next
		
		image.WritePixels(pixels, 0, 0, image.Width(), image.Height())

		image.SetHandle(image.Width() / 2, image.Height() / 2)

		SetColor(255, 255, 255)
		Cls(0, 0, 0)
	End
	
	Method Collide:Bool(sprite:Sprite)
		Local rect1:Rect = New Rect
		
		rect1.x = x - image.HandleX()
		rect1.y = y - image.HandleY()
		rect1.width = image.Width()
		rect1.height = image.Height()
		
		Local rect2:Rect = New Rect

		rect2.x = sprite.x - sprite.image.HandleX()
		rect2.y = sprite.y - sprite.image.HandleY()
		rect2.width = sprite.image.Width()
		rect2.height = sprite.image.Height()
		
		If rect1.IntersectWith(rect2)
			collisionRect = rect1.Intersection(rect2)
			If collisionRect <> Null Then
				For Local iy:Int = collisionRect.y Until collisionRect.height + collisionRect.y
					For Local ix:Int = collisionRect.x Until collisionRect.width + collisionRect.x
						Local a1:Int = (GetPixel(ix - rect1.x, iy - rect1.y) Shr 24) & $ff
						Local a2:Int = (sprite.GetPixel(ix - rect2.x, iy - rect2.y) Shr 24) & $ff
						If a1 > 0 And a2 > 0
							Return True
						End
					Next
				Next
			End
		Else
			collisionRect = Null
		End
		Return False
	End
	
	Method GetPixel:Int(x:Int, y:Int)
		Return pixels[x + y * image.Width()]
	End
End

Class Rect
	Field x:Int
	Field y:Int
	Field width:Int
	Field height:Int
	
	Method New(x:Int, y:Int, width:Int, height:Int)
		Self.x = x
		Self.y = y
		Self.width = width
		Self.height = height
	End
	
	Method IntersectWith:Bool(r:Rect)
		Local tw:Int = Self.width
		Local th:Int = Self.height
		Local rw:Int = r.width
		Local rh:Int = r.height
		If (rw <= 0 Or rh <= 0 Or tw <= 0 Or th <= 0)
			Return False
		End
		Local tx:Int = Self.x
		Local ty:Int = Self.y
		Local rx:Int = r.x
		Local ry:Int = r.y
		rw += rx
		rh += ry
		tw += tx
		th += ty

		Return ((rw < rx Or rw > tx) And
				(rh < ry Or rh > ty) And
				(tw < tx Or tw > rx) And
				(th < ty Or th > ry))
	End
	
	Method Intersection:Rect(r:Rect)
		Local tx1:Int = Self.x
		Local ty1:Int = Self.y
		Local rx1:Int = r.x
		Local ry1:Int = r.y
		
		Local tx2:Float = tx1
		Local ty2:Float = ty1
		Local rx2:Float = rx1
		Local ry2:Float = ry1
		
		tx2 += Self.width
		ty2 += Self.height
		rx2 += r.width
		ry2 += r.height
		
		If (tx1 < rx1) Then tx1 = rx1
		If (ty1 < ry1) Then ty1 = ry1
		If (tx2 > rx2) Then tx2 = rx2
		If (ty2 > ry2) Then ty2 = ry2
		tx2 -= tx1
		ty2 -= ty1

		If (tx2 < -2147483648) tx2 = -2147483648
		If (ty2 < -2147483648) ty2 = -2147483648
		Return New Rect(tx1, ty1, Int(tx2), Int(ty2))
	End
	
	Method ToString:String()
		Return x + "," + y + "," + width + "," + height
	End
	
End



therevills(Posted 2015) [#5]
Try this, load the image directly into the image variable:

Class Sprite
	Field image:Image
	Field pixels:Int[]
	Field createImages:Bool
	Field x:Float, y:Float
	Field collisionRect:Rect
	
	Method New()
		image = LoadImage("monkey.png")
		pixels = New Int[image.Width() * image.Height()]
		createImages = True
	End


	Method CreateImages:Void()
	If Not createImages Return
	createImages = False
	Cls(0, 0, 0)
	DrawImage(image, 0, 0)



Luis(Posted 2015) [#6]
I keep coming "Memory access violation"


therevills(Posted 2015) [#7]
Where is your monkey.png located? It needs to be in the data folder for your project.


Luis(Posted 2015) [#8]
Principal.monkey
Principal.data/monkey.png


therevills(Posted 2015) [#9]
Works fine here....

https://dl.dropboxusercontent.com/u/35103024/pixeltest.zip


Luis(Posted 2015) [#10]
therevills : Memory access violation :'(


Luis(Posted 2015) [#11]
Function and thank me, it was my mistake, the folder. * Data was not well written, so I did not come out that mistake, but thanks! :)