Jazzie,
I like your engine, I've tried using fredborg's viewport rotation function (found here: http://www.blitzbasic.com/Community/posts.php?topic=42799#478997
but it only works for a second when "A" is pressed. The code is below, I'm not sure how to put it in a code window yet:
Framework brl.glmax2d
Import brl.random
Import brl.pngloader
SetGraphicsDriver GLMax2DDriver()
' ----- CONSTANTS -----
Const scrWidth=640,scrHeight=480 ' screen resolution
Const scrDepth=32 ' bitdept, *** change as required ***
Const scrHertz=75 ' refresh rate (this is nice and smooth, but change if required).
Const tileWidth=32,tileHeight=32 ' dimension of tiles
Const tileMain=1,tileBack=2,tilePlayer=3 ' frame numbers for tiles
Const playerSpeed=4 ' pixels for player to move each update
Const mapWidth=64,mapHeight=64 ' size of map
Const marginX=(scrWidth-tileWidth)/2 ' margin between edge of screen and centre (horizontal)
Const marginY=(scrHeight-tileHeight)/2 ' margin between edge of screen and centre (vertical)
' ----- GLOBALS -----
SeedRnd MilliSecs()
Global ms#,fps#,msTot#,msCnt#,msAvg#
' ----- TYPE / METHOD DECLARATIONS -----
Type player
Field mapX,mapY ' map block co-ordinates (top left if more than one square occupied)
Field x,y ' pixel co-ordinates
Function Create:player() ' create a player with the starting x and y map co-ordinates
Local sx,sy
p:player=New player ' create player
Repeat
sx=Rand(1,mapWidth-1) ' choose random x position
sy=Rand(1,mapHeight-1) ' choose random y position
Until lev.Read(sx,sy)=0
p.mapX=sx ' set starting x (map co-ordinate)
p.mapY=sy ' set starting y (map co-ordinate)
p.x=sx*tileWidth ' set x position (pixels)
p.y=sy*tileHeight ' set y position (pixels)
Return p
End Function
Method Update()
Local dx=(KeyDown(key_right)-KeyDown(key_left))*playerSpeed ' get player input for the x direction
Local dy=(KeyDown(key_down)-KeyDown(key_up))*playerSpeed ' get player input for the y direction
If dy Then ' check vertical movement
If MapCollision(x+dx,y+dy) Then ' check if we can move
If dx Then ' can't move, but might be trying to move diagonally
If MapCollision(x,y+dy) Then ' can we move straight up or down?
dy=0 ' still can't move, so don't allow
EndIf
Else
dy=0 ' not trying to move at angle, so don't allow
EndIf
EndIf
EndIf
If dx Then ' do the same for horizontal
If MapCollision(x+dx,y+dy) Then
If dy Then
If MapCollision(x+dx,y) Then
dx=0
EndIf
Else
dx=0
EndIf
EndIf
EndIf
x:+dx ' update co-ordinates
y:+dy
mapX=Floor(x/tileWidth) ' update map position
mapY=Floor(y/tileHeight)
End Method
Method Draw(sx,sy)
DrawImage imgTiles,sx,sy,tilePlayer ' draw plater with supplied screen co-ordinates
DrawText "World position: "+x+","+y,0,0
DrawText "Map position: "+mapX+","+mapY,0,16
End Method
End Type
Type level
Field map[mapWidth,mapHeight] ' define our map array
Method Read(x,y) ' method to read tile at map position
Return map[x,y]
End Method
Method Write(x,y,z) ' method to write to a map position
map[x,y]=z
End Method
Method Draw(ox,oy) ' draw map at specified offset (calculated in RenderGame)
SetBlend solidblend ' set blending to solid to erase screen
TileImage imgTiles,ox/2,oy/2,tileBack ' draw our parallax background image
SetBlend alphablend ' set blending to alpha (not needed, as our tiles are square)
' now go through map and display each tile, but ignore any blank tiles for additional speed
For Local y=0 Until mapHeight
For Local x=0 Until mapWidth
If Read(x,y) Then DrawImage imgTiles,x*tileWidth+ox,y*tileHeight+oy,Read(x,y)
Next
Next
End Method
End Type
Rem
NOTE: The Draw() method above could be optimised further to only loop through those tiles that appear
on-screen, but is not really needed at the moment as only those images that appear on-screen will be
rendered anyway. Larger and more complicated ganes may benefit if every bit of available processing power
is needed. The rendering process of this demo runs at under 1ms on a P4 2.4GHZ with Radeon 9800 Pro.
EndRem
' ----- SET UP GRAPHICS -----
Graphics scrWidth,scrHeight,scrDepth,scrHertz ' change graphics mode
HideMouse ' hide the mouse pointer
Global imgTiles=LoadAnimImage("tiles.png",tileWidth,tileHeight,0,4) ' load the tiles
' ----- INITIALISE MAP -----
Global lev:level=New level ' create a level
For Local x=0 Until mapWidth ' draw the top and bottom borders
lev.Write(x,0,tileMain)
lev.Write(x,mapHeight-1,tileMain)
Next
For Local y=0 Until mapHeight ' draw the left and right borders
lev.Write(0,y,tileMain)
lev.Write(mapWidth-1,y,tileMain)
Next
For Local i=1 To 50 ' draws50 random lines of the wall tile
dir=Rand(0,1)
x=Rand(1,mapWidth-2)
y=Rand(1,mapHeight-2)
l=Rand(2,30)
For Local j=0 Until l
If dir Then
lev.Write(x,y,tileMain)
x:+1
If x=mapWidth Then Exit
Else
lev.Write(x,y,tileMain)
y:+1
If y=mapHeight Then Exit
EndIf
Next
Next
' ----- INITIALISE PLAYER -----
Global face:player=player.Create() ' create a player
' ----- MAIN LOOP -----
While Not KeyHit(key_escape)
face.Update ' get player input and update position
RenderGame ' render the screen
Wend
' ----- RENDER FUNCTION -----
Function RenderGame()
If KeyHit(KEY_A)
Sangle:+1
EndIf
Local time=MilliSecs() ' used to time how long this takes (before flipping, which waits for vsync)
Local t$ ' used to format render time
Local lx,ly,px,py ' level offsets and players on-screen position
' check horizontal placement
If face.x>=marginX And face.x<=((mapWidth-1)*tileWidth-marginX) Then ' if player within central area
px=marginX ' player stays in centre
lx=px-face.x ' level offset is player's x minus the margin between the screen edge and player
ElseIf face.x<marginX ' check if player near left edge
px=face.x ' yes, so on-screen position is same as x
lx=0 ' and level offset is it's left edge
Else ' otherwise player is near right edge of level
px=marginX+marginX-((mapWidth-1)*tileWidth-face.x) ' calculate player's position based on level width
lx=-mapWidth*tileWidth+scrWidth ' adjust level's position so that right edge is same as screen edge
EndIf
' check for vertical placement - same as above, but on the y axis
If face.y>=marginY And face.y<=((mapHeight-1)*tileHeight-marginY) Then
py=marginY
ly=py-face.y
ElseIf face.y<marginY
py=face.y
ly=0
Else
py=marginY+marginY-((mapHeight-1)*tileHeight-face.y)
ly=-mapHeight*tileHeight+scrHeight
EndIf
lev.Draw(lx,ly) ' draw the level at the calculated offset
face.Draw(px,py) ' draw the player at the calculated on-screen position
ms=MilliSecs()-time ' work out how long it took to draw
msTot:+ms ' add to total render time for previous frames
msCnt:+1 ' increase count (for average)
msAvg=msTot/msCnt ' calculate average render time
If msAvg Then fps=1000/msAvg ' make sure we won't get a /0 error and calculate *estimated* FPS
t=msAvg ' convert to string for displaying on screen
DrawText "Avg render time: "+t[..5]+"ms ("+Int(fps)+" FPS)",0,32 ' write to screen
SetViewRotation (Sangle)
Flip ' flip the buffers so we can see everything and clear any rubbish from memory.
End Function
' ----- CHECKS IF ANY SQUARES AT PIXEL CO-ORDINATES ARE OCCUPIED -----
Function MapCollision(x,y)
Local mx,my
mx=Floor(x/tileWidth) ' get map position
my=Floor(y/tileHeight)
If lev.Read(mx,my) Then Return True ' check top left
If (x Mod tileWidth) Then If lev.Read(mx+1,my) Then Return True ' check top right
If (y Mod tileHeight) Then
If lev.Read(mx,my+1) Then ' check bottom left
Return True
ElseIf (x Mod tileWidth) Then
If lev.Read(mx+1,my+1) Then Return True ' check bottom right#
EndIf
EndIf
Return False
End Function
Rem
bbdoc: Set the rotation of the viewport
about: SetViewRotation allows you to rotate the entire viewport, so that all
drawing is rotated according to the @angle parameter.
endrem
Function SetViewRotation(angle:Float)
Global o_angle:Float
glMatrixMode GL_PROJECTION
glRotatef angle-o_angle,0,0,1
o_angle=angle
glMatrixMode GL_MODELVIEW
glLoadIdentity
End Function
Rem
bbdoc: Set the offset of the viewport
about: SetViewOffset allows you to offset the entire viewport, so that all
drawing is offset according to the @offsetx and @offsety parameters.
endrem
Function SetViewOffset(offsetx:Float,offsety:Float)
Global o_offsetx:Float
Global o_offsety:Float
glMatrixMode GL_PROJECTION
glTranslatef offsetx-o_offsetx,offsety-o_offsety,0
o_offsetx = offsetx
o_offsety = offsety
glMatrixMode GL_MODELVIEW
glLoadIdentity
End Function
Rem
bbdoc: Set the zoom factor of the viewport
about: SetViewZoom allows you to zoom all drawn elements at once, instead
of scaling each individual element. Use the @zoom parameter to define the
level of zoom, a value of 0 is the default zoom, >0 zooms in, <0 zooms out.
endrem
Function SetViewZoom(zoom:Float)
Global o_zoom:Float
glMatrixMode GL_PROJECTION
glScalef 1.0+(zoom-o_zoom),1.0+(zoom-o_zoom),1.0+(zoom-o_zoom)
o_zoom = zoom
glMatrixMode GL_MODELVIEW
glLoadIdentity
End Function
I like your engine, I've tried using fredborg's viewport rotation function (found here: http://www.blitzbasic.com/Community/posts.php?topic=42799#478997
but it only works for a second when "A" is pressed. The code is below, I'm not sure how to put it in a code window yet:
Framework brl.glmax2d
Import brl.random
Import brl.pngloader
SetGraphicsDriver GLMax2DDriver()
' ----- CONSTANTS -----
Const scrWidth=640,scrHeight=480 ' screen resolution
Const scrDepth=32 ' bitdept, *** change as required ***
Const scrHertz=75 ' refresh rate (this is nice and smooth, but change if required).
Const tileWidth=32,tileHeight=32 ' dimension of tiles
Const tileMain=1,tileBack=2,tilePlayer=3 ' frame numbers for tiles
Const playerSpeed=4 ' pixels for player to move each update
Const mapWidth=64,mapHeight=64 ' size of map
Const marginX=(scrWidth-tileWidth)/2 ' margin between edge of screen and centre (horizontal)
Const marginY=(scrHeight-tileHeight)/2 ' margin between edge of screen and centre (vertical)
' ----- GLOBALS -----
SeedRnd MilliSecs()
Global ms#,fps#,msTot#,msCnt#,msAvg#
' ----- TYPE / METHOD DECLARATIONS -----
Type player
Field mapX,mapY ' map block co-ordinates (top left if more than one square occupied)
Field x,y ' pixel co-ordinates
Function Create:player() ' create a player with the starting x and y map co-ordinates
Local sx,sy
p:player=New player ' create player
Repeat
sx=Rand(1,mapWidth-1) ' choose random x position
sy=Rand(1,mapHeight-1) ' choose random y position
Until lev.Read(sx,sy)=0
p.mapX=sx ' set starting x (map co-ordinate)
p.mapY=sy ' set starting y (map co-ordinate)
p.x=sx*tileWidth ' set x position (pixels)
p.y=sy*tileHeight ' set y position (pixels)
Return p
End Function
Method Update()
Local dx=(KeyDown(key_right)-KeyDown(key_left))*playerSpeed ' get player input for the x direction
Local dy=(KeyDown(key_down)-KeyDown(key_up))*playerSpeed ' get player input for the y direction
If dy Then ' check vertical movement
If MapCollision(x+dx,y+dy) Then ' check if we can move
If dx Then ' can't move, but might be trying to move diagonally
If MapCollision(x,y+dy) Then ' can we move straight up or down?
dy=0 ' still can't move, so don't allow
EndIf
Else
dy=0 ' not trying to move at angle, so don't allow
EndIf
EndIf
EndIf
If dx Then ' do the same for horizontal
If MapCollision(x+dx,y+dy) Then
If dy Then
If MapCollision(x+dx,y) Then
dx=0
EndIf
Else
dx=0
EndIf
EndIf
EndIf
x:+dx ' update co-ordinates
y:+dy
mapX=Floor(x/tileWidth) ' update map position
mapY=Floor(y/tileHeight)
End Method
Method Draw(sx,sy)
DrawImage imgTiles,sx,sy,tilePlayer ' draw plater with supplied screen co-ordinates
DrawText "World position: "+x+","+y,0,0
DrawText "Map position: "+mapX+","+mapY,0,16
End Method
End Type
Type level
Field map[mapWidth,mapHeight] ' define our map array
Method Read(x,y) ' method to read tile at map position
Return map[x,y]
End Method
Method Write(x,y,z) ' method to write to a map position
map[x,y]=z
End Method
Method Draw(ox,oy) ' draw map at specified offset (calculated in RenderGame)
SetBlend solidblend ' set blending to solid to erase screen
TileImage imgTiles,ox/2,oy/2,tileBack ' draw our parallax background image
SetBlend alphablend ' set blending to alpha (not needed, as our tiles are square)
' now go through map and display each tile, but ignore any blank tiles for additional speed
For Local y=0 Until mapHeight
For Local x=0 Until mapWidth
If Read(x,y) Then DrawImage imgTiles,x*tileWidth+ox,y*tileHeight+oy,Read(x,y)
Next
Next
End Method
End Type
Rem
NOTE: The Draw() method above could be optimised further to only loop through those tiles that appear
on-screen, but is not really needed at the moment as only those images that appear on-screen will be
rendered anyway. Larger and more complicated ganes may benefit if every bit of available processing power
is needed. The rendering process of this demo runs at under 1ms on a P4 2.4GHZ with Radeon 9800 Pro.
EndRem
' ----- SET UP GRAPHICS -----
Graphics scrWidth,scrHeight,scrDepth,scrHertz ' change graphics mode
HideMouse ' hide the mouse pointer
Global imgTiles=LoadAnimImage("tiles.png",tileWidth,tileHeight,0,4) ' load the tiles
' ----- INITIALISE MAP -----
Global lev:level=New level ' create a level
For Local x=0 Until mapWidth ' draw the top and bottom borders
lev.Write(x,0,tileMain)
lev.Write(x,mapHeight-1,tileMain)
Next
For Local y=0 Until mapHeight ' draw the left and right borders
lev.Write(0,y,tileMain)
lev.Write(mapWidth-1,y,tileMain)
Next
For Local i=1 To 50 ' draws50 random lines of the wall tile
dir=Rand(0,1)
x=Rand(1,mapWidth-2)
y=Rand(1,mapHeight-2)
l=Rand(2,30)
For Local j=0 Until l
If dir Then
lev.Write(x,y,tileMain)
x:+1
If x=mapWidth Then Exit
Else
lev.Write(x,y,tileMain)
y:+1
If y=mapHeight Then Exit
EndIf
Next
Next
' ----- INITIALISE PLAYER -----
Global face:player=player.Create() ' create a player
' ----- MAIN LOOP -----
While Not KeyHit(key_escape)
face.Update ' get player input and update position
RenderGame ' render the screen
Wend
' ----- RENDER FUNCTION -----
Function RenderGame()
If KeyHit(KEY_A)
Sangle:+1
EndIf
Local time=MilliSecs() ' used to time how long this takes (before flipping, which waits for vsync)
Local t$ ' used to format render time
Local lx,ly,px,py ' level offsets and players on-screen position
' check horizontal placement
If face.x>=marginX And face.x<=((mapWidth-1)*tileWidth-marginX) Then ' if player within central area
px=marginX ' player stays in centre
lx=px-face.x ' level offset is player's x minus the margin between the screen edge and player
ElseIf face.x<marginX ' check if player near left edge
px=face.x ' yes, so on-screen position is same as x
lx=0 ' and level offset is it's left edge
Else ' otherwise player is near right edge of level
px=marginX+marginX-((mapWidth-1)*tileWidth-face.x) ' calculate player's position based on level width
lx=-mapWidth*tileWidth+scrWidth ' adjust level's position so that right edge is same as screen edge
EndIf
' check for vertical placement - same as above, but on the y axis
If face.y>=marginY And face.y<=((mapHeight-1)*tileHeight-marginY) Then
py=marginY
ly=py-face.y
ElseIf face.y<marginY
py=face.y
ly=0
Else
py=marginY+marginY-((mapHeight-1)*tileHeight-face.y)
ly=-mapHeight*tileHeight+scrHeight
EndIf
lev.Draw(lx,ly) ' draw the level at the calculated offset
face.Draw(px,py) ' draw the player at the calculated on-screen position
ms=MilliSecs()-time ' work out how long it took to draw
msTot:+ms ' add to total render time for previous frames
msCnt:+1 ' increase count (for average)
msAvg=msTot/msCnt ' calculate average render time
If msAvg Then fps=1000/msAvg ' make sure we won't get a /0 error and calculate *estimated* FPS
t=msAvg ' convert to string for displaying on screen
DrawText "Avg render time: "+t[..5]+"ms ("+Int(fps)+" FPS)",0,32 ' write to screen
SetViewRotation (Sangle)
Flip ' flip the buffers so we can see everything and clear any rubbish from memory.
End Function
' ----- CHECKS IF ANY SQUARES AT PIXEL CO-ORDINATES ARE OCCUPIED -----
Function MapCollision(x,y)
Local mx,my
mx=Floor(x/tileWidth) ' get map position
my=Floor(y/tileHeight)
If lev.Read(mx,my) Then Return True ' check top left
If (x Mod tileWidth) Then If lev.Read(mx+1,my) Then Return True ' check top right
If (y Mod tileHeight) Then
If lev.Read(mx,my+1) Then ' check bottom left
Return True
ElseIf (x Mod tileWidth) Then
If lev.Read(mx+1,my+1) Then Return True ' check bottom right#
EndIf
EndIf
Return False
End Function
Rem
bbdoc: Set the rotation of the viewport
about: SetViewRotation allows you to rotate the entire viewport, so that all
drawing is rotated according to the @angle parameter.
endrem
Function SetViewRotation(angle:Float)
Global o_angle:Float
glMatrixMode GL_PROJECTION
glRotatef angle-o_angle,0,0,1
o_angle=angle
glMatrixMode GL_MODELVIEW
glLoadIdentity
End Function
Rem
bbdoc: Set the offset of the viewport
about: SetViewOffset allows you to offset the entire viewport, so that all
drawing is offset according to the @offsetx and @offsety parameters.
endrem
Function SetViewOffset(offsetx:Float,offsety:Float)
Global o_offsetx:Float
Global o_offsety:Float
glMatrixMode GL_PROJECTION
glTranslatef offsetx-o_offsetx,offsety-o_offsety,0
o_offsetx = offsetx
o_offsety = offsety
glMatrixMode GL_MODELVIEW
glLoadIdentity
End Function
Rem
bbdoc: Set the zoom factor of the viewport
about: SetViewZoom allows you to zoom all drawn elements at once, instead
of scaling each individual element. Use the @zoom parameter to define the
level of zoom, a value of 0 is the default zoom, >0 zooms in, <0 zooms out.
endrem
Function SetViewZoom(zoom:Float)
Global o_zoom:Float
glMatrixMode GL_PROJECTION
glScalef 1.0+(zoom-o_zoom),1.0+(zoom-o_zoom),1.0+(zoom-o_zoom)
o_zoom = zoom
glMatrixMode GL_MODELVIEW
glLoadIdentity
End Function