Skip to content

Instantly share code, notes, and snippets.

@GWRon
Created December 5, 2021 09:35
Show Gist options
  • Save GWRon/d518fa3c86ff45b604366de24b60bbdf to your computer and use it in GitHub Desktop.
Save GWRon/d518fa3c86ff45b604366de24b60bbdf to your computer and use it in GitHub Desktop.
' J I G S A W - G A M E E X A M P L E
'
' Author Midimaster www.midimaster.de
'
' Copyright: Public Domain
' Version 1.01
' last change: now for BlitzMax NG and BlitzMax 1.51
'
' your own pngs:
' a transparent "jigmiddle.png" with a smaller black rectangle in the exact center,
' a transparent "jignose.png" with one example for the black jigsaw nose looking to the right
' the transparent border around the rectangle needs to be exact the size to take the nose
' both pngs and the inner rectangle need to be quadratic with a odd side length
' the "foto.png" size needs to be a multiple of the inner rectangle size.
SuperStrict
Framework Brl.StandardIO
Import Random.Xoshiro
Import Brl.Retro
Import Brl.LinkedList
Import Brl.GLMax2D
Import Brl.PNGLoader
Import "dig.base.gfx.imagehelper.bmx"
Global Nr%=0, Move%
'Delevopers Flags:
Const SORTED% = 0 ' set to 1 to get sorted JigSaw pieces during Development/Debugging
Const ONLY_MASK% = 0 ' set to 1 to see only JigSaw piece masks during Development/Debugging
Const SHOW_TYP% = 0 ' set to 1 to see additional Typ information (like "FHHW" )next to the piece during Development/Debugging
Const LIGHT_OFF% = 0 ' set to 1 to switch off border lighting during Development/Debugging
Const ONLY_BLUE% = 0 ' set to 1 to switch off pixel picking from JigFoto during Development/Debugging
Const NO_SHADOW% = 0 ' set to 1 to hide shadow layer during Development/Debugging
Const SHOW_GRID% = 2 ' set to 1 to show placement grid for tiles and 2 to show puzzle outline
Const SHOW_TILE_ORIGIN% = 0 ' set to 1 to handle of the tiles
AppTitle="JigSaw example by midimaster.de"
Graphics 1400,900
Global jigsaw:TJigsaw = new TJigsaw
jigSaw.Init()
SetClsColor 55,111,111
Repeat
Cls
SetColor(255,255,255)
SetBlend(alphablend)
jigsaw.Update()
MouseAction()
jigsaw.Draw()
Flip(1)
Until AppTerminate()
Function MouseAction()
If MouseDown(1)
If move = 0
local oldSelectedTile:TJigsawTile = jigsaw.selectedTile
jigsaw.SelectTile( jigSaw.GetTileAtXY(MouseX() - jigsaw.x, MouseY() - jigsaw.y) )
If jigsaw.selectedTile
If jigsaw.selectedTile <> oldSelectedTile
jigsaw.DragTile(jigsaw.selectedTile)
jigsaw.HoverTile(jigsaw.selectedTile)
Endif
move = 1
MouseXSpeed()
MouseYSpeed()
EndIf
ElseIf move = 1
jigsaw.selectedTile.x :+ MouseXSpeed()
jigsaw.selectedTile.y :+ MouseYSpeed()
EndIf
ElseIf MouseDown(2)
If move = 0
local oldSelectedTile:TJigsawTile = jigsaw.selectedTile
jigsaw.SelectTile(jigsaw.GetTileAtXY(MouseX() - jigsaw.x, MouseY() - jigsaw.y) )
If jigsaw.selectedTile
If jigsaw.selectedTile <> oldSelectedTile
jigsaw.DragTile(jigsaw.selectedTile)
Endif
move = 2
MouseXSpeed()
MouseYSpeed()
EndIf
Else
jigsaw.selectedTile.rotation :+ MouseXSpeed()
EndIf
ElseIf move > 0
if jigsaw.TryToPlaceTile(jigsaw.selectedTile)
jigsaw.selectedTile = Null
Endif
move = 0
Else
jigsaw.DropTile(jigsaw.selectedTile)
EndIf
End Function
Type TJigsawTileConfig
Field size:Int
Field baseSize:Int
Field borderSize:Int
Field basePixShape:TPixmap
Field basePixNoseShape:TPixmap
End Type
Type TJigsawTile
Field sideTypes:Int[]
Field sideOffsets:Int[]
Field x:Int, y:Int
Field rotation:Int
Field column:Int, row:Int
Field tileConfig:TJigsawTileConfig
Field placed:Int
Field selected:Int
Field pixTile:TPixmap, pixShape:TPixmap
Field imgTile:TImage, imgShadow:TImage, imgOutline:TImage, imgGridBackground:TImage
Const outlineOffset:Int = 0
Const shadowBlurStrength:Float = 0.25
Const shadowAlpha:Float = 0.25
Const shadowOffset:Int = 4
Const draggedShadowOffset:Int = 8
Const draggedShadowAlpha:Float = 0.4
Const selectedOffset:Int = -2
Method Init:TJigsawTile(jigsawPicture:TPixmap, tileConfig:TJigsawTileConfig, sideTypes:Int[], sideOffsets:Int[], column:Int, row:Int)
self.column = column
self.row = row
self.sideTypes = sideTypes
self.sideOffsets = sideOffsets
self.tileConfig = tileConfig
self._GenerateShape()
self._GenerateTileImage(jigsawPicture)
self._GenerateShadowImage()
self._GenerateOutlineImage()
self._GenerateGridBackgroundImage()
MidHandleImage(imgTile)
MidHandleImage(imgShadow)
MidHandleImage(imgOutline)
Return self
End Method
Method DrawShadow(offsetX:Int, offsetY:Int)
If NO_SHADOW Then Return
Local oldA:Float = GetAlpha()
SetRotation(rotation)
If selected
SetAlpha(draggedShadowAlpha * oldA)
DrawImage(imgShadow, x + offsetX + draggedShadowOffset + selectedOffset, y + offsetY + draggedShadowOffset + selectedOffset)
Else
SetAlpha(shadowAlpha * oldA)
DrawImage(imgShadow, x + offsetX + shadowOffset, y + offsetY + shadowOffset)
EndIf
SetRotation(0)
SetAlpha(oldA)
End Method
Method DrawOutline(offsetX:Int, offsetY:Int)
SetRotation(rotation)
if selected
DrawImage(imgOutline, x + offsetX + outlineOffset + selectedOffset, y + offsetY + outlineOffset + selectedOffset)
else
DrawImage(imgOutline, x + offsetX + outlineOffset, y + offsetY + outlineOffset)
endif
SetRotation(0)
End Method
Method Draw(offsetX:Int, offsetY:Int)
SetRotation(rotation)
if selected
DrawImage(imgTile, x + offsetX + selectedOffset, y + offsetY + selectedOffset)
else
DrawImage(imgTile, x + offsetX, y + offsetY)
endif
SetRotation(0)
If SHOW_TYP = 1
local t:String
For local i:int = EachIn sideTypes
if i = TJigsaw.SIDE_HOLE then t :+ "H"
if i = TJigsaw.SIDE_NOSE then t :+ "N"
if i = TJigsaw.SIDE_EMPTY then t :+ "F"
Next
DrawText(t, x + offsetX + 70, y + offsetY + 70)
EndIf
if SHOW_TILE_ORIGIN
DrawOval(x + offsetX - 5, y + offsetY - 5, 10, 10)
Endif
End Method
Method _GenerateShape()
pixShape = tileConfig.basePixShape.Copy()
Local noseSize:Int = tileConfig.basePixNoseShape.width
Select sideTypes[0]
Case TJigsaw.SIDE_HOLE
_CutMask(pixShape, tileConfig.basePixNoseShape, TJigsaw.SIDE_TOP, tileConfig.borderSize + sideOffsets[0], tileConfig.borderSize)
Case TJigsaw.SIDE_NOSE
_AddMask(pixShape, tileConfig.basePixNoseShape, TJigsaw.SIDE_TOP, tileConfig.borderSize + sideOffsets[0], tileConfig.borderSize - 1)
End Select
Select sideTypes[1]
Case TJigsaw.SIDE_HOLE
_CutMask(pixShape, tileConfig.basePixNoseShape, TJigsaw.SIDE_RIGHT, tileConfig.borderSize + tileConfig.baseSize - 1, tileConfig.borderSize + sideOffsets[1])
Case TJigsaw.SIDE_NOSE
_AddMask(pixShape, tileConfig.basePixNoseShape, TJigsaw.SIDE_RIGHT, tileConfig.basesize + tileConfig.borderSize, tileConfig.borderSize + sideOffsets[1])
End Select
Select sideTypes[2]
Case TJigsaw.SIDE_HOLE
_CutMask(pixShape, tileConfig.basePixNoseShape, TJigsaw.SIDE_BOTTOM, tileConfig.borderSize + sideOffsets[2], tileConfig.baseSize + tileConfig.borderSize - 1)
Case TJigsaw.SIDE_NOSE
_AddMask(pixShape, tileConfig.basePixNoseShape, TJigsaw.SIDE_BOTTOM, tileConfig.borderSize + sideOffsets[2], tileConfig.baseSize + tileConfig.borderSize)
End Select
Select sideTypes[3]
Case TJigsaw.SIDE_HOLE
_CutMask(pixShape, tileConfig.basePixNoseShape, TJigsaw.SIDE_LEFT, tileConfig.borderSize, tileConfig.borderSize + sideOffsets[3])
Case TJigsaw.SIDE_NOSE
_AddMask(pixShape, tileConfig.basePixNoseShape, TJigsaw.SIDE_LEFT, tileConfig.borderSize - 1, tileConfig.borderSize + sideOffsets[3])
End Select
End Method
Method _GenerateShadowImage()
'shadow must be a bit bigger
Local shadowPix:TPixmap = CreatePixmap(pixShape.width + 10, pixShape.height + 10, pixShape.format)
shadowPix.ClearPixels(0)
shadowPix.Paste(pixShape, 5, 5)
blurPixmap(shadowPix, shadowBlurStrength, $ffffff00)
imgShadow = LoadImage(shadowPix, FILTEREDIMAGE)
End Method
Method _GenerateOutlineImage()
'outline must be a bit bigger
imgOutline = ConvertToOutLine(pixShape, 3, 0.75, $ffffffff, 4)
Local outlinePix:TPixmap = LockImage(imgOutline)
blurPixmap(outlinePix, 0.7, $FF000000)
imgOutline = LoadImage(outlinePix, FILTEREDIMAGE)
End Method
Method _GenerateGridBackgroundImage()
'outline must be a bit bigger
imgGridBackground = ConvertToOutLine(pixShape, 2, 0.8, $66ffffff, 4)
Local outlinePix:TPixmap = LockImage(imgGridBackground)
blurPixmap(outlinePix, 0.7, $00000000)
imgGridBackground = LoadImage(outlinePix, FILTEREDIMAGE)
End Method
Method _GenerateTileImage(jigsawTexture:TPixmap)
pixTile = CreatePixmap(pixShape.width, pixShape.height, PF_RGBA8888)
pixTile.ClearPixels(0)
If ONLY_MASK = 0
For Local pixX:Int = 0 Until pixTile.width
For Local pixY:Int = 0 Until pixTile.height
local maskAlpha:Int = (pixShape.ReadPixel(pixX, pixY) Shr 24) & $ff
'skip invisible
If maskAlpha <= 0 Then Continue
Local sourceColor:Int
If ONLY_BLUE = 0
sourceColor = jigsawTexture.ReadPixel(pixX + (column-1) * tileConfig.baseSize - tileConfig.borderSize, pixY + (row-1) * tileConfig.baseSize - tileConfig.borderSize)
Else
sourceColor = $ff7777ff
EndIf
'remove source alpha and add mask alpha
pixTile.WritePixel(pixX, pixY, (sourceColor & $00FFFFFF) + (maskAlpha * $1000000) )
Next
Next
_AddLightEffect(pixTile, pixShape)
EndIf
imgTile = LoadImage(pixTile, FILTEREDIMAGE)
End Method
Function _AddLightEffect(pix:TPixmap, mask:TPixmap, lightDirection:int = 0)
If LIGHT_OFF=1 Return
Local now:Int=0
Local c:Int
'scan along pixel lines and light up first opacque pixel and
'darken the ones before the first transparent one, rinse repeat
For Local pixX:Int = 0 Until pix.width
now = 0
For Local pixY:Int = 0 Until pix.height
c = mask.ReadPixel(pixX, pixY)
If now = 0 and c <> 0
pix.WritePixel(pixX, pixY, RiseColor(1.3, pix.ReadPixel(pixX, pixY)))
if pixY + 1 < pix.height
pix.WritePixel(pixX, pixY + 1, RiseColor(1.4, pix.ReadPixel(pixX, pixY + 1)))
EndIf
now = 1
ElseIf now = 1 and c = 0
if pixY - 2 >= 0
pix.WritePixel(pixX, pixY - 2, RiseColor(0.7, pix.ReadPixel(pixX, pixY - 2)))
EndIf
If pixY - 1 >= 0
pix.WritePixel(pixX, pixY - 1, RiseColor(0.8, pix.ReadPixel(pixX, pixY - 1)))
EndIf
now = 0
EndIf
Next
Next
For Local pixY:Int = 0 Until pix.height
now = 0
For Local pixX:Int = 0 Until pix.width
c = mask.ReadPixel(pixX, pixY)
If now = 0 and c <> 0
pix.WritePixel(pixX, pixY, RiseColor(1.4, pix.ReadPixel(pixX, pixY)))
If pixX + 1 < pix.width
pix.WritePixel(pixX + 1, pixY, RiseColor(1.4, pix.ReadPixel(pixX + 1, pixY)))
EndIf
now = 1
ElseIf now = 1 and c = 0
If pixX - 2 >= 0
pix.WritePixel(pixX - 2, pixY, RiseColor(0.7, pix.ReadPixel(pixX - 2, pixY)))
EndIf
If pixX - 1 >= 0
pix.WritePixel(pixX - 1, pixY, RiseColor(0.7, pix.ReadPixel(pixX - 1, pixY)))
EndIf
now = 0
EndIf
Next
Next
'yep, function in a function!
Function RiseColor:Int(f:Float, color:Int)
Local r:Int = (color & $00ff0000) / $10000
Local g:Int = (color & $0000ff00) / $100
Local b:Int = (color & $000000ff)
r = int(Min(r*f, 255)) * $10000
g = int(Min(g*f, 255)) * $100
b = int(Min(b*f, 255))
Return (color & $ff000000) | r | g | b
End Function
End Function
Function _AddMask(base:TPixmap, mask:TPixmap, side:Int, offsetX:Int, offsetY:Int)
if base.width < mask.width + offsetX Then Throw "TJigsawTile - mask too big (width)"
if base.height < mask.height + offsetY Then Throw "TJigsawTile - mask too big (height)"
For Local maskX:Int = 0 Until mask.width
For Local maskY:Int = 0 Until mask.height
Local maskColor:Int = mask.ReadPixel(maskX, maskY)
If maskColor = 0 Then continue
Select side
Case TJigsaw.SIDE_RIGHT
base.WritePixel(offsetX + maskX, offsetY + maskY, maskColor)
Case TJigsaw.SIDE_LEFT
base.WritePixel(offsetX - maskX, offsetY + maskY, maskColor)
Case TJigsaw.SIDE_BOTTOM
base.WritePixel(offsetX + maskY, offsetY + maskX, maskColor)
Case TJigsaw.SIDE_TOP
base.WritePixel(offsetX + maskY, offsetY - maskX, maskColor)
End Select
Next
Next
End Function
Function _CutMask(base:TPixmap, mask:TPixmap, side:Int, offsetX:Int, offsetY:Int)
if base.width < mask.width + offsetX Then Throw "TJigsawTile - mask too big (width)"
if base.height < mask.height + offsetY Then Throw "TJigsawTile - mask too big (height)"
For Local maskX:Int = 0 Until mask.width
For Local maskY:Int = 0 Until mask.height
'for cuts/holes we reduce alpha of the pixmap's pixel
'by what is left (so NOSE alpha 255 cuts 100%, 0 cuts 0%)
Local maskColor:Int = mask.ReadPixel(maskX, maskY)
If maskColor = 0 Then continue
Local maskAlpha:Int = (maskColor Shr 24) & $ff
Select side
Case TJigsaw.SIDE_RIGHT
'remove original alpha and add back "alpha mix"
base.WritePixel(offsetX - maskX, offsetY + maskY, (base.ReadPixel(offsetX - maskX, offsetY + maskY) & $00FFFFFF) + (255 - maskAlpha) * $1000000)
Case TJigsaw.SIDE_LEFT
'remove original alpha and add back "alpha mix"
base.WritePixel(offsetX + maskX, offsetY + maskY, (base.ReadPixel(offsetX + maskX, offsetY + maskY) & $00FFFFFF) + (255 - maskAlpha) * $1000000)
Case TJigsaw.SIDE_BOTTOM
'remove original alpha and add back "alpha mix"
base.WritePixel(offsetX + maskY, offsetY - maskX, (base.ReadPixel(offsetX + maskY, offsetY - maskX) & $00FFFFFF) + (255 - maskAlpha) * $1000000)
Case TJigsaw.SIDE_TOP
'remove original alpha and add back "alpha mix"
base.WritePixel(offsetX + maskY, offsetY + maskX, (base.ReadPixel(offsetX + maskY, offsetY + maskX) & $00FFFFFF) + (255 - maskAlpha) * $1000000)
End Select
Next
Next
End Function
End Type
Type TJigsaw
'tiles are ordered by their creation order - or manual drag/drop
Field tiles:TList = New TList
Field tilesReversed:TList = New TList
Field Columns%, Rows%
'position of jigsaw on screen
Field x:Int, y:Int
Field w:Int=-1, h:Int=-1
'offset of image from jigsaw origin
Field imageOffsetX:int=100, imageOffsetY:Int=100
Field selectedTile:TJigsawTile
Field hoveredTile:TJigsawTile
Field tileConfig:TJigsawTileConfig
Field jigsawPicture:TPixmap
Const SIDE_EMPTY:Int = 0
Const SIDE_NOSE:Int = 1
Const SIDE_HOLE:Int = 2
Const SIDE_LEFT:Int = 4
Const SIDE_TOP:Int = 8
Const SIDE_RIGHT:Int = 16
Const SIDE_BOTTOM:Int = 32
Method Init()
tileConfig = new TJigsawTileConfig
tileConfig.basePixShape = LoadPixmap("jigMiddle.png")
tileConfig.basePixNoseShape = LoadPixmap("jigNOSE.png")
jigsawPicture = LoadPixmap("jigfoto.png")
if not tileConfig.basePixShape then throw "jigMiddle.png not found"
if not tileConfig.basePixNoseShape then throw "jigNOSE.png not found"
if not jigsawPicture then throw "jigfoto.png not found"
CalculateSizes()
GenerateTiles()
If SORTED=0
ShuffleTiles()
Else
For Local tile:TJigsawTile = eachin tiles
tile.rotation = 0
tile.x = (tile.column-1)*(tileConfig.size-20) + 100
tile.y = (tile.row-1)*(tileConfig.size-20) + 100
Next
EndIf
End Method
Method CalculateSizes()
Print "GenerateTiles()"
tileConfig.size = Min(tileConfig.basePixShape.width, tileConfig.basePixShape.height)
tileConfig.baseSize = _FindTileBaseWidth(tileConfig.basePixShape)
tileConfig.borderSize = (tileConfig.size - tileConfig.baseSize) / 2
Print " size=" + tileConfig.size + " (base=" + tileConfig.baseSize + " borders=" + tileConfig.borderSize + ")"
'if image is bigger than puzzle size (eg some pixels too wide)
'we simply ignore the "rest"
'but if too small to fit at least once ... we fail
columns = jigsawPicture.width / tileConfig.baseSize
rows = jigsawPicture.height / tileConfig.baseSize
Print " columns=" + columns + " rows=" + rows
If columns = 0 or rows = 0
RuntimeError "ERROR: picture too small (" + jigsawPicture.width + "x" + jigsawPicture.height + ", minimum required: " + tileConfig.baseSize + "x" + tileConfig.baseSize + ")"
EndIf
End Method
'scans y-center from left to right to find first opacque point
'assume inner part is "centered" (left space = right space)
Function _FindTileBaseWidth:Int(pix:TPixmap)
For Local x:Int = 0 until pix.width
If pix.ReadPixel(x, pix.height/2)<>0
Return pix.width - 2 * x
EndIf
Next
RuntimeError "_FindTileBaseWidth: Failed to find non-transparent point on vertical center line"
End Function
Method GenerateTiles()
Print "GenerateTiles()"
SeedRnd MilliSecs()
For Local row:Int = 1 To rows
For Local col:Int = 1 To columns
local sideTypes:Int[] = new Int[4]
local sideOffsets:Int[] = new Int[4]
'top
'first row?
If row = 1
sideTypes[0] = SIDE_EMPTY
Else
Local neighbourTop:TJigsawTile = GetTile(col,row-1)
If neighbourTop
If neighbourTop.sideTypes[2] = SIDE_HOLE
sideTypes[0] = SIDE_NOSE
Else
sideTypes[0] = SIDE_HOLE
EndIf
sideOffsets[0] = neighbourTop.sideOffsets[2]
EndIf
EndIf
'right
'last column?
If col = columns
sideTypes[1] = SIDE_EMPTY
Else
Select Rand(0,1)
Case 0
sideTypes[1] = SIDE_HOLE
Case 1
sideTypes[1] = SIDE_NOSE
End Select
'TODO: anders definieren
sideOffsets[1] = Rand(30, 65)
EndIf
'bottom
'last row?
If row = rows
sideTypes[2] = SIDE_EMPTY
Else
Select Rand(0,1)
Case 0
sideTypes[2] = SIDE_HOLE
Case 1
sideTypes[2] = SIDE_NOSE
End Select
'TODO: anders definieren
sideOffsets[2] = Rand(25, 70)
EndIf
'left
'first column?
If col = 1
sideTypes[3] = SIDE_EMPTY
Else
Local neighbourLeft:TJigsawTile = GetTile(col - 1,row)
If neighbourLeft
If neighbourLeft.sideTypes[1] = SIDE_HOLE
sideTypes[3] = SIDE_NOSE
Else
sideTypes[3] = SIDE_HOLE
EndIf
sideOffsets[3] = neighbourLeft.sideOffsets[1]
EndIf
EndIf
Local tile:TJigsawTile = New TJigsawTile.Init(jigsawPicture, tileConfig, sideTypes, sideOffsets, col, row)
tiles.AddFirst(tile)
tilesReversed.AddLast(tile)
Next
Next
End Method
Method ShuffleTiles:int()
For local tile:TJigsawTile = EachIn tiles
tile.rotation = Rand(0,359)
tile.x = Rand(GraphicsWidth()-300) + 200
tile.y = Rand(GraphicsHeight()-300) + 200
Next
End Method
Method GetTile:TJigsawTile(column:Int, row:Int)
For Local t:TJigsawTile = EachIn tiles
If t.column = column And t.row = row
Return t
EndIf
Next
Return Null
End Method
Method IsTileOverTargetCell:Int(tile:TJigsawTile)
'print "IsTileOverTargetCell: " + " x="+tile.x +" y="+tile.y
'print "IsTileOverTargetCell: " + " currCol="+((tile.x - imageOffsetX + tileConfig.baseSize/2) / tileConfig.baseSize + 1)+" tarCol="+tile.column
'print "IsTileOverTargetCell: " + " currRow="+((tile.y - imageOffsetY + tileConfig.baseSize/2) / tileConfig.baseSize + 1)+" tarRow="+tile.row
Return ((tile.x - imageOffsetX + tileConfig.baseSize/2) / tileConfig.baseSize) + 1 = tile.column And ((tile.y - imageOffsetY + tileConfig.baseSize/2) / tileConfig.baseSize) + 1 = tile.row
End Method
Method PlaceTileOnTargetCell(tile:TJigsawTile)
tile.placed = True
tile.rotation = 0
tile.x = (tile.column - 1) * tileConfig.baseSize + imageOffsetX
tile.y = (tile.row - 1) * tileConfig.baseSize + imageOffsetY
tile.placed = True
End Method
Method TryToPlaceTile:Int(tile:TJigsawTile)
if not tile then Return False
If IsTileOverTargetCell(tile)
'expect tile to be rotated almost into original rotation
tile.rotation = (tile.rotation + 360) Mod 360
If tile.rotation < 10 Or tile.rotation > 350
PlaceTileOnTargetCell(tile)
DropTile(tile)
tiles.Remove(tile)
tiles.AddFirst(tile)
tilesReversed = tiles.Reversed()
Return True
EndIf
EndIf
Return False
End Method
Method Update()
if not selectedTile
hoveredTile = jigsaw.GetTileAtXY(MouseX() - x, MouseY() - y)
endif
End Method
Method Draw()
SetColor 50,50,50
if w=-1 and h=-1
DrawRect(x, y, GraphicsWidth() - x, GraphicsHeight() - y)
else
DrawRect(x, y, w, h)
endif
SetColor 152, 122, 35
DrawRect(imageOffsetX - tileConfig.baseSize/2 - 3, imageOffsetY - tileConfig.baseSize/2 - 3, tileConfig.baseSize * columns + 6, tileConfig.baseSize * rows + 6)
SetColor 222,155,55
DrawRect(imageOffsetX - tileConfig.baseSize/2 + 3,imageOffsetY - tileConfig.baseSize/2 + 3, tileConfig.baseSize * columns - 6, tileConfig.baseSize * rows - 6)
SetColor 255,255,255
'puzzle grid
if SHOW_GRID = 1
For local r:int = 0 to rows ' from 0 so it contains "begin" too
DrawLine(imageOffsetX, imageOffsetY + r*tileConfig.baseSize, imageOffsetX + columns*tileConfig.baseSize, imageOffsetY + r*tileConfig.baseSize)
Next
For local c:int = 0 to columns
DrawLine(imageOffsetX + c*tileConfig.baseSize, imageOffsetY, imageOffsetX + c*tileConfig.baseSize, imageOffsetY + rows*tileConfig.baseSize)
Next
Elseif SHOW_GRID = 2
For local t:TJigsawTile = EachIn tiles
DrawImage(t.imgGridBackground, imageOffsetX + (t.column-1)*tileConfig.baseSize - tileConfig.baseSize/2 - tileConfig.borderSize - 5, imageOffsetY + (t.row-1)*tileConfig.baseSize - tileConfig.baseSize/2 - tileConfig.borderSize - 5)
Next
EndIf
DrawTiles()
End Method
Method DrawTiles()
'draw layer of base tiles (so exclude top most one)
For Local t:TJigsawTile= EachIn tiles
if t <> selectedTile Then t.DrawShadow(x, y)
Next
'draw tile itself
For Local t:TJigsawTile = EachIn tiles
If t = selectedTile Then t.DrawShadow(x, y)
t.Draw(x, y)
if hoveredTile = t
SetBlend LIGHTBLEND
SetAlpha Float(0.1 + 0.1 * Sin(Millisecs() * 0.2))
t.Draw(x, y)
SetBlend ALPHABLEND
SetAlpha 1.0
EndIf
if hoveredTile = t
SetAlpha 0.9
t.DrawOutline(x, y)
SetAlpha 1.0
EndIf
'If t = hoveredTile Then t.DrawOutline(x, y)
Next
'draw hover on top of all
if hoveredTile
SetAlpha 0.4
hoveredTile.DrawOutline(x, y)
SetAlpha 1.0
EndIf
End Method
Method HoverTile:Int(t:TJigsawTile)
If t <> hoveredTile
hoveredTile = t
Return True
endif
Return False
End Method
Method SelectTile:Int(t:TJigsawTile)
print "select"
if selectedTile then selectedTile.selected = False
If t <> selectedTile
if t then t.selected = True
selectedTile = t
Return True
endif
Return False
End Method
Method DropTile(t:TJigsawTile)
if t
if t = selectedTile then selectedTile = Null
t.selected = False
endif
End Method
Method DragTile(t:TJigsawTile)
'move it on top
tiles.Remove(t)
tiles.AddLast(t)
tilesReversed = tiles.Reversed()
End Method
Method GetTileAtXY:TJigsawTile(x:Int, y:Int, lookupRange:int = -1)
if lookupRange = -1 then lookupRange = tileConfig.baseSize / 2
For Local t:TJigsawTile = EachIn tilesReversed
if t.placed then continue
If Abs(x - t.x) < lookupRange
If Abs(y - t.y) < lookupRange
Return t
EndIf
EndIf
Next
Return Null
End Method
End Type
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment