The easiest way to code a 3d Platformer.

Post your FreeBASIC source, examples, tips and tricks here. Please don’t post code without including an explanation.
Post Reply
relsoft
Posts: 1767
Joined: May 27, 2005 10:34
Location: Philippines
Contact:

The easiest way to code a 3d Platformer.

Post by relsoft »

Hi, This started of as a proof of concept for a DS game. It was a $#@$& to port to the DS though (-8 to +8 vertex coordinate limits) but I got it working. I thought I might share the FB versions here.

The idea is to be able to make a 3d engine using standard 2D screen coordinate system.

Update:

Textured version now up for grabs!

http://rel.phatcode.net/junk.php?id=126

Map is text based so you can edit the level from inside code.
Code is now heavily commented.

Also added:

Code: Select all

1. A way to texture the level using a tileset
2. 3 camera scrolling behaviors
3. Parallax Background
4. Sprites
Images by Marc Russel from gfx-lib fuzed

DS screen:
Image

1. Simple

Code: Select all

''*****************************************************************************
'' 
''   2.5D Engine
''   Relminator (Richard Eric M. Lope)
''	 http://rel.phatcode.net
''
''	 This is probably the easiest way to make a 3d game
''   Features:
''   * 1:1 ratio of 3D coords to Screen
''   * Collisions are in tilebased 2D
''   * Rendering can be camera based (uber fast)
''   * Any 2D tilebased game can be converted to this
''
''   Controls
''   
''   SPACE = Jump
''   ARROW KEYS = Move
''   F1 = Paper mario mode?
''   F2/F3 = Zoom
''
''*****************************************************************************

#include once "fbgfx.bi"
#include once "/gl/gl.bi" 
#include once "/gl/glu.bi"   


''*****************************************************************************
declare sub GL_Screen_Init(byval screen_wid as integer, byval screen_hei as integer, byval flags as integer = 0)

'' Drawing stuff
''*****************************************************************************
declare sub DrawCube( x as single, y as single, z as single, Size as single, Red as single, Green as single, Blue as single ) 
declare sub DrawMap()


''*****************************************************************************
const as integer SCREEN_WIDTH = 640
const as integer SCREEN_HEIGHT = 480

const as integer TILE_SIZE = 32


const as integer MAP_WID = SCREEN_WIDTH\TILE_SIZE      '' 20
const as integer MAP_HEI = SCREEN_HEIGHT\TILE_SIZE      '' 15

const as integer FALSE = 0
const as integer TRUE = not FALSE

const as single Gravity = 0.75
const as single JumpHeight = 15


''*****************************************************************************
dim shared as integer Map(MAP_WID-1,MAP_HEI-1) =>_
{{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},_  ''1
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''2
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''3
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''4
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''5
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},_   ''6
{1,0,0,0,0,0,0,0,0,0,1,0,0,0,1},_   ''7
{1,0,0,0,0,0,0,1,0,0,1,0,0,0,1},_   ''8
{1,0,0,0,0,1,0,0,0,0,0,0,0,0,1},_   ''9
{1,0,0,0,0,0,0,0,0,0,0,0,1,0,1},_   ''10
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''11
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''12
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},_   ''13
{1,0,0,0,0,0,1,0,0,0,0,0,1,0,1},_   ''14
{1,0,0,0,0,0,0,0,0,0,0,1,0,0,1},_   ''15
{1,0,0,0,0,0,1,0,0,0,0,1,0,0,1},_   ''16
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''17
{1,0,0,0,0,1,0,0,0,0,0,0,0,0,1},_   ''18
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},_   ''19
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}}


''*****************************************************************************
''
''
''
''*****************************************************************************
type Player

	x		as single
	y		as single
	speed	as single
	xv		as single
	yv		as single
	wid		as integer
	hei		as integer
	
	CanJump as integer
	
	declare constructor()
	declare function CollideFloors(byval ix as integer, byval iy as integer, byref TileY as integer, Map() as integer ) as integer
	declare function CollideWalls(byval ix as integer, byval iy as integer, byref TileX as integer, Map() as integer ) as integer
	declare sub DoStuff()
	declare sub CollideOnMap( Map() as integer )
	declare sub Draw3D()
	
end type

constructor Player()
	x = 32 * 2 
	y = 32 * 5 
	speed = 4.5
	wid = 24
	hei = 48
	CanJump = false
End Constructor



function Player.CollideWalls(byval ix as integer, byval iy as integer, byref TileX as integer, Map() as integer ) as integer
	
	dim as integer TileYpixels = iy - (iy mod TILE_SIZE)   '' Pixel of the player's head snapped to map grid
	dim as integer TestEnd = iy + hei					   '' Foot of the player
	
	TileX = ix\TILE_SIZE								   '' Current X map coord the player is on + x-velocity(+ width when moving right)
	
	dim as integer TileY = TileYpixels\TILE_SIZE		   '' Current Y map coord of the player's head
	
	'' Scan downwards from head to foot if we collided with a tile on the right or left
	while (TileYpixels <= TestEnd)
		if (Map(TileX, TileY))	then return true		   '' Found a tile

		TileY += 1										   '' Next tile downward
		TileYpixels +=TILE_SIZE							   '' Next tile pixel downward
		
	Wend
	
	return false
End Function

function Player.CollideFloors(byval ix as integer, byval iy as integer, byref TileY as integer, Map() as integer ) as integer
	
	dim as integer TileXpixels = ix - (ix mod TILE_SIZE)
	dim as integer TestEnd = ix + wid
	
	TileY = iy\TILE_SIZE
	
	dim as integer TileX = TileXpixels\TILE_SIZE
	
	while (TileXpixels <= TestEnd)
		if (Map(TileX, TileY))	then return true	

		TileX += 1
		TileXpixels +=TILE_SIZE
		
	Wend
	
	return false
End Function



sub Player.DoStuff()

	xv = 0
	
	if multikey(FB.SC_LEFT) then 
		xv = -speed
	EndIf
	
    if multikey(FB.SC_RIGHT) then 
    	xv = speed
    EndIf
    
    if multikey(FB.SC_SPACE) then 
	    if( CanJump ) then
	    	yv = -JumpHeight
	    	CanJump = false
	    end if
    EndIf
    
    
    
End Sub

sub Player.CollideOnMap( Map() as integer )
	
	dim as Integer TileX, TileY

	if( xv > 0 ) then
		
		if( CollideWalls( x + xv + wid, y, TileX, Map() ) ) then
			x = TileX * TILE_SIZE - wid - 1
		else
			x += xv
		EndIf
			
	elseif( xv < 0 ) then
		
		if( CollideWalls( x + xv, y, TileX, Map() ) ) then
			x = ( TileX + 1 ) * TILE_SIZE + 1
		else
			x += xv
		EndIf
		
	EndIf
	
	if( yv < 0 ) then
		
		if( CollideFloors( x, y + yv, TileY, Map() ) ) then   '' hit the roof
			y = ( TileY + 1 ) * TILE_SIZE + 1
			yv = 0    
		else
			y += yv
			yv += Gravity
		EndIf
			
	else
		
		if( CollideFloors( x, y + yv + hei, TileY, Map() ) ) then
			y = ( TileY ) * TILE_SIZE - hei - 1
			yv = 1
			if not multikey(FB.SC_SPACE) then CanJump = true
		else
			y += yv
			yv += Gravity
			CanJump = false
		EndIf
		
	EndIf
	
	
End Sub


sub Player.Draw3D()

	'' Draws the player in 3D	
	dim as single SizeX = Wid/2.0
	dim as single SizeY = Hei/2.0
	
	
	glColor4f( 1, 0, 1, 1 )
	glPushMatrix()
		glTranslatef( x + Wid/2, y + Hei/2.0, 0) '' Offset by Size/2 so that we draw from top-left at (0,0)
		glBegin(GL_QUADS)
			glVertex3f(-SizeX, -SizeY,  0)
			glVertex3f( SizeX, -SizeY,  0)
			glVertex3f( SizeX,  SizeY,  0)
			glVertex3f(-SizeX,  SizeY,  0)			
		glEnd()
	glPopMatrix()
	
	
end sub

	
''*****************************************************************************
''
''
''
''*****************************************************************************

Type Vector2D

	x as Single
	y as Single
	z as single
	
end type

Type Camera
	
	
	declare Constructor()
	declare sub Follow( x as single, y as single )
	declare sub Look()
	declare sub Look( value as single )
	declare sub Zoom( value as single )

	
	
	Position as Vector2D 
	Target as Vector2D 
	Up as Vector2D 
	
	EyeDistanceFromScreen as integer

end type


constructor Camera()

	EyeDistanceFromScreen = TILE_SIZE * 18   '' Distance of player's eye from screen
	
	Position.x = 0
	Position.y = 0
	Position.z = EyeDistanceFromScreen       '' Yep we are drawing at z = 0 so pos should be positive
	
	Target.x = 0
	Target.y = 0
	Target.z = 0
	
	Up.x = 0
	Up.y = 1
	Up.z = 0
	
	
end constructor	

sub Camera.Follow( x as single, y as single )

	
	Position.x = x
	Position.y = y - TILE_SIZE * 1    		'' offset a little above so we look a little down
	Position.z = EyeDistanceFromScreen      '' move zpos n units from screen to eye
	
	Target.x = x
	Target.y = y
	Target.z = 0
	
	Up.x = 0
	Up.y = 1
	Up.z = 0
	
end sub


sub Camera.Look()

	
	gluLookAt( Position.x, Position.y, Position.z,_    '' camera pos
			   Target.x, Target.y, Target.z,_     	  '' camera target
               Up.x, Up.y, Up.z)

end sub



sub Camera.Zoom( value as single )

	EyeDistanceFromScreen +=value

end sub
	

''*****************************************************************************
sub main()
	
	
	dim as integer Frame = 0
	 
	dim as Camera Cam
	dim as Player Mario
	 
	GL_Screen_Init( SCREEN_WIDTH, SCREEN_HEIGHT )   ''Set up GL screen

	
	do
		
		Frame += 1

		Mario.DoStuff()     '' Do player movements
    
		Mario.CollideOnMap( Map() )		'' Do collisions in 2D
		
		
		'' Zoom if you want
		if( multikey(FB.SC_F2) ) then Cam.Zoom(1.62)
		if( multikey(FB.SC_F3) ) then Cam.Zoom(-1.62)
		
		
		
		glMatrixMode( GL_MODELVIEW )
		glLoadIdentity() 
		glPolygonMode( GL_FRONT, GL_FILL )
		glPolygonMode( GL_BACK, GL_FILL )
		glEnable( GL_DEPTH_TEST )
		glDepthFunc( GL_LEQUAL )
		
		glDisable( GL_TEXTURE_2D )
	
		
		glColor4ub( 255, 255, 255, 255 )

		'' Move cam according to player's pos
		Cam.Follow( Mario.x, Mario.y )
		
		'' reverse y direction for oldskool coords(Easy GL2D = happy)
		glScalef( 1, -1, 1 )
		
		'' Look
		Cam.Look()
		
		'' Paper mario?
		if( multikey(FB.SC_F1) ) then glRotatef( 20, 0, 1, 0 )
		
		'' Clear screen
		glClear(GL_COLOR_BUFFER_BIT OR GL_DEPTH_BUFFER_BIT)

		'' Draw 3D stuff
		glPushMatrix()   
					
			DrawMap()
			Mario.Draw3D()

		glPopMatrix()    
		
		'' limit FPS
		dim as single TimeStart = timer
		while( (timer - TimeStart) < (1.0/60.0) )
			sleep 1,1
		wend
		
		
		flip
		
	Loop until multikey(FB.SC_ESCAPE)

	
	
End Sub



main()


end








''*****************************************************************************
'' Temp way to draw our 32x32 tiles
sub DrawCube( x as single, y as single, z as single, Size as single, Red as single, Green as single, Blue as single )

	glColor4f( Red, Green, Blue, 1 )
	
	glPushMatrix()
		glTranslatef( x + Size, y + Size, z)  '' Offset by Size so that we draw from top-left at (0,0)
	
		glBegin(GL_QUADS)
			'' Front Face
			glColor3f( 1, 0, 0)
			glVertex3f(-Size, -Size,  Size)
			glColor3f( 0, 1, 0)
			glVertex3f( Size, -Size,  Size)
			glColor3f( 0, 0, 1)
			glVertex3f( Size,  Size,  Size)
			glColor3f( 1, 1, 1)
			glVertex3f(-Size,  Size,  Size)
			
			glColor4f( 1, 1, 0, 1 )
	
			'' Back Face
			glVertex3f(-Size, -Size, -Size)
			glVertex3f(-Size,  Size, -Size)
			glVertex3f( Size,  Size, -Size)
			glVertex3f( Size, -Size, -Size)
			'' Top Face
			glVertex3f(-Size,  Size, -Size)
			glVertex3f(-Size,  Size,  Size)
			glVertex3f( Size,  Size,  Size)
			glVertex3f( Size,  Size, -Size)
			'' Bottom Face
			glVertex3f(-Size, -Size, -Size)
			glVertex3f( Size, -Size, -Size)
			glVertex3f( Size, -Size,  Size)
			glVertex3f(-Size, -Size,  Size)
			'' Right face
			glVertex3f( Size, -Size, -Size)
			glVertex3f( Size,  Size, -Size)
			glVertex3f( Size,  Size,  Size)
			glVertex3f( Size, -Size,  Size)
			'' Left Face
			glVertex3f(-Size, -Size, -Size)
			glVertex3f(-Size, -Size,  Size)
			glVertex3f(-Size,  Size,  Size)
			glVertex3f(-Size,  Size, -Size)
		glEnd()
	
	glPopMatrix()
	
	glColor4f( 1, 1, 1, 1 )
	
	
end sub


'' Draws the map in 3D
sub DrawMap()

	for y as integer = 0 to (MAP_HEI - 1)
		for x as integer = 0 to (MAP_WID - 1)
			if( Map(x,y) > 0 ) then			
				DrawCube( x * TILE_SIZE, y * TILE_SIZE, 0, TILE_SIZE/2, 0, 1, 0 )
			end if
		next x	
	next y
	
end sub


''=============================================================================
''
''    Sets up OpenGL for 2d mode
''
''=============================================================================
sub GL_Screen_Init(byval screen_wid as integer, byval screen_hei as integer, byval flags as integer = 0)
	
	if flags then
		screenres screen_wid, screen_hei, 32, 2, FB.GFX_OPENGL or flags
	else
		screenres screen_wid, screen_hei, 32, 2, FB.GFX_OPENGL
	endif
	
	
	'screen information 
	dim w as integer, h as integer 
	'OpenGL params for gluerspective 
	dim FOVy as double            'Field of view angle in Y 
	dim Aspect as double          'Aspect of screen 
	dim znear as double           'z-near clip distance 
	dim zfar as double            'z-far clip distance 

	'using screen info w and h as params 
	glViewport(0, 0, screen_wid, screen_hei)
	
	'Set current Mode to projection(ie: 3d) 
	glMatrixMode(GL_PROJECTION) 
	
	'Load identity matrix to projection matrix 
	glLoadIdentity() 

	'Set gluPerspective params 
	FOVy = 90/2                                     '45 deg fovy 
	Aspect = screen_wid / screen_hei
	znear = 1                                       'Near clip 
	zfar = 1500                                     'far clip 
	
	'use glu Perspective to set our 3d frustum dimension up 
	gluPerspective(FOVy, aspect, znear, zfar) 
	
	'Modelview mode 
	'ie. Matrix that does things to anything we draw 
	'as in lines, points, tris, etc. 
	glMatrixMode(GL_MODELVIEW) 
	'load identity(clean) matrix to modelview 
	glLoadIdentity() 
	
	glShadeModel(GL_SMOOTH)                 'set shading to smooth(try GL_FLAT) 
	glClearColor(0.0, 0.0, 0.0, 1.0)        'set Clear color to BLACK 
	glClearDepth(1.0)                       'Set Depth buffer to 1(z-Buffer) 
	glEnable(GL_DEPTH_TEST)                 'Enable Depth Testing so that our z-buffer works 
	
	'compare each incoming pixel z value with the z value present in the depth buffer 
	'LEQUAL means than pixel is drawn if the incoming z value is less than 
	'or equal to the stored z value 
	glDepthFunc(GL_LEQUAL) 
	
	'have one or more material parameters track the current color 
	'Material is your 3d model 
	glEnable(GL_COLOR_MATERIAL) 


    'Enable Texturing 
    glEnable(GL_TEXTURE_2D) 
    

   	'Tell openGL that we want the best possible perspective transform 
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST) 
	
	'Disable Backface culling
	glDisable (GL_CULL_FACE)
	
	glPolygonMode(GL_FRONT, GL_FILL) 
	
	'' enable blending for transparency 
	glEnable(GL_BLEND)    	    
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
	
	glDisable( GL_DEPTH_TEST )
	
	glEnable( GL_ALPHA_TEST )
	glAlphaFunc(GL_GREATER, 0)


	glDisable(GL_STENCIL_TEST)
	glDisable(GL_TEXTURE_1D)
	glDisable(GL_LIGHTING)
	glDisable(GL_LOGIC_OP)
	glDisable(GL_DITHER)
	glDisable(GL_FOG)

	glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST)
	glHint(GL_LINE_SMOOTH_HINT , GL_FASTEST)

	glPointSize( 1 )
	glLineWidth( 1 )
	
	
end sub




2. Dynamic Camera

Code: Select all

''*****************************************************************************
'' 
''   2.5D Engine (Dynamic camera)
''   Relminator (Richard Eric M. Lope)
''	 http://rel.phatcode.net
''
''	 This is probably the easiest way to make a 3d game
''   Features:
''   * 1:1 ratio of 3D coords to Screen
''   * Collisions are in tilebased 2D
''   * Rendering can be camera based (uber fast)
''   * Any 2D tilebased game can be converted to this
''
''   Controls
''   
''   SPACE = Jump
''   ARROW KEYS = Move
''   F1 = Paper mario mode?
''   F2/F3 = Zoom
''
''*****************************************************************************

#include once "fbgfx.bi"
#include once "/gl/gl.bi" 
#include once "/gl/glu.bi"   


''*****************************************************************************
declare sub GL_Screen_Init(byval screen_wid as integer, byval screen_hei as integer, byval flags as integer = 0)

'' Drawing stuff
''*****************************************************************************
declare sub DrawCube( x as single, y as single, z as single, Size as single, Red as single, Green as single, Blue as single ) 
declare sub DrawMap()


''*****************************************************************************
const as integer SCREEN_WIDTH = 640
const as integer SCREEN_HEIGHT = 480

const as integer TILE_SIZE = 32


const as integer MAP_WID = SCREEN_WIDTH\TILE_SIZE      '' 20
const as integer MAP_HEI = SCREEN_HEIGHT\TILE_SIZE      '' 15

const as integer FALSE = 0
const as integer TRUE = not FALSE

const as single Gravity = 0.75
const as single JumpHeight = 15


''*****************************************************************************
dim shared as integer Map(MAP_WID-1,MAP_HEI-1) =>_
{{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},_  ''1
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''2
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''3
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''4
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''5
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},_   ''6
{1,0,0,0,0,0,0,0,0,0,1,0,0,0,1},_   ''7
{1,0,0,0,0,0,0,1,0,0,1,0,0,0,1},_   ''8
{1,0,0,0,0,1,0,0,0,0,0,0,0,0,1},_   ''9
{1,0,0,0,0,0,0,0,0,0,0,0,1,0,1},_   ''10
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''11
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''12
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},_   ''13
{1,0,0,0,0,0,1,0,0,0,0,0,1,0,1},_   ''14
{1,0,0,0,0,0,0,0,0,0,0,1,0,0,1},_   ''15
{1,0,0,0,0,0,1,0,0,0,0,1,0,0,1},_   ''16
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''17
{1,0,0,0,0,1,0,0,0,0,0,0,0,0,1},_   ''18
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},_   ''19
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}}


''*****************************************************************************
''
''
''
''*****************************************************************************
type Player

	x		as single
	y		as single
	speed	as single
	xv		as single
	yv		as single
	wid		as integer
	hei		as integer
	
	CanJump as integer
	
	declare constructor()
	declare function CollideFloors(byval ix as integer, byval iy as integer, byref TileY as integer, Map() as integer ) as integer
	declare function CollideWalls(byval ix as integer, byval iy as integer, byref TileX as integer, Map() as integer ) as integer
	declare sub DoStuff()
	declare sub CollideOnMap( Map() as integer )
	declare sub Draw3D()
	
end type

constructor Player()
	x = 32 * 2 
	y = 32 * 5 
	speed = 4.5
	wid = 24
	hei = 48
	CanJump = false
End Constructor



function Player.CollideWalls(byval ix as integer, byval iy as integer, byref TileX as integer, Map() as integer ) as integer
	
	dim as integer TileYpixels = iy - (iy mod TILE_SIZE)   '' Pixel of the player's head snapped to map grid
	dim as integer TestEnd = iy + hei					   '' Foot of the player
	
	TileX = ix\TILE_SIZE								   '' Current X map coord the player is on + x-velocity(+ width when moving right)
	
	dim as integer TileY = TileYpixels\TILE_SIZE		   '' Current Y map coord of the player's head
	
	'' Scan downwards from head to foot if we collided with a tile on the right or left
	while (TileYpixels <= TestEnd)
		if (Map(TileX, TileY))	then return true		   '' Found a tile

		TileY += 1										   '' Next tile downward
		TileYpixels +=TILE_SIZE							   '' Next tile pixel downward
		
	Wend
	
	return false
End Function

function Player.CollideFloors(byval ix as integer, byval iy as integer, byref TileY as integer, Map() as integer ) as integer
	
	dim as integer TileXpixels = ix - (ix mod TILE_SIZE)
	dim as integer TestEnd = ix + wid
	
	TileY = iy\TILE_SIZE
	
	dim as integer TileX = TileXpixels\TILE_SIZE
	
	while (TileXpixels <= TestEnd)
		if (Map(TileX, TileY))	then return true	

		TileX += 1
		TileXpixels +=TILE_SIZE
		
	Wend
	
	return false
End Function



sub Player.DoStuff()

	xv = 0
	
	if multikey(FB.SC_LEFT) then 
		xv = -speed
	EndIf
	
    if multikey(FB.SC_RIGHT) then 
    	xv = speed
    EndIf
    
    if multikey(FB.SC_SPACE) then 
	    if( CanJump ) then
	    	yv = -JumpHeight
	    	CanJump = false
	    end if
    EndIf
    
    
    
End Sub

sub Player.CollideOnMap( Map() as integer )
	
	dim as Integer TileX, TileY

	if( xv > 0 ) then
		
		if( CollideWalls( x + xv + wid, y, TileX, Map() ) ) then
			x = TileX * TILE_SIZE - wid - 1
		else
			x += xv
		EndIf
			
	elseif( xv < 0 ) then
		
		if( CollideWalls( x + xv, y, TileX, Map() ) ) then
			x = ( TileX + 1 ) * TILE_SIZE + 1
		else
			x += xv
		EndIf
		
	EndIf
	
	if( yv < 0 ) then
		
		if( CollideFloors( x, y + yv, TileY, Map() ) ) then   '' hit the roof
			y = ( TileY + 1 ) * TILE_SIZE + 1
			yv = 0    
		else
			y += yv
			yv += Gravity
		EndIf
			
	else
		
		if( CollideFloors( x, y + yv + hei, TileY, Map() ) ) then
			y = ( TileY ) * TILE_SIZE - hei - 1
			yv = 1
			if not multikey(FB.SC_SPACE) then CanJump = true
		else
			y += yv
			yv += Gravity
			CanJump = false
		EndIf
		
	EndIf
	
	
End Sub


sub Player.Draw3D()

	'' Draws the player in 3D	
	dim as single SizeX = Wid/2.0
	dim as single SizeY = Hei/2.0
	
	
	glColor4f( 1, 0, 1, 1 )
	glPushMatrix()
		glTranslatef( x + Wid/2, y + Hei/2.0, 0) '' Offset by Size/2 so that we draw from top-left at (0,0)
		glBegin(GL_QUADS)
			glVertex3f(-SizeX, -SizeY,  0)
			glVertex3f( SizeX, -SizeY,  0)
			glVertex3f( SizeX,  SizeY,  0)
			glVertex3f(-SizeX,  SizeY,  0)			
		glEnd()
	glPopMatrix()
	
	
end sub

	
''*****************************************************************************
''
''
''
''*****************************************************************************

Type Vector2D

	x as Single
	y as Single
	z as single
	
end type

Type Camera
	
	
	declare Constructor()
	declare sub Follow( x as single, y as single )
	declare sub Follow( x as single, y as single, skew as integer )
	declare sub Look()
	declare sub Zoom( value as single )

	
	
	Position as Vector2D 
	Target as Vector2D 
	Up as Vector2D 
	
	EyeDistanceFromScreen as integer

end type


constructor Camera()

	EyeDistanceFromScreen = TILE_SIZE * 18   '' Distance of player's eye from screen
	
	Position.x = 0
	Position.y = 0
	Position.z = EyeDistanceFromScreen       '' Yep we are drawing at z = 0 so pos should be positive
	
	Target.x = 0
	Target.y = 0
	Target.z = 0
	
	Up.x = 0
	Up.y = 1
	Up.z = 0
	
	
end constructor	

sub Camera.Follow( x as single, y as single )

	
	Position.x = x
	Position.y = y - TILE_SIZE * 1    		'' offset a little above so we look a little down
	Position.z = EyeDistanceFromScreen      '' move zpos n units from screen to eye
	
	Target.x = x
	Target.y = y
	Target.z = 0
	
	Up.x = 0
	Up.y = 1
	Up.z = 0
	
end sub


sub Camera.Follow( x as single, y as single, skew as integer )

	static as single rot = 0
	if( skew > 0 ) then
		if( rot < 100 ) then rot += 5  
	elseif ( skew < 0 ) then
		if( rot > -100 ) then rot -= 5
	else  '' 0
		if( rot > 0 ) then rot -= 5
		if( rot < 0 ) then rot += 5
	end if
	
	Position.x = x - rot 
	Position.y = y - TILE_SIZE * 1    		'' offset a little above so we look a little down
	Position.z = EyeDistanceFromScreen      '' move zpos n units from screen to eye
	
	Target.x = x + rot
	Target.y = y
	Target.z = 0
	
	Up.x = 0
	Up.y = 1
	Up.z = 0
	
end sub


sub Camera.Look()

	
	gluLookAt( Position.x, Position.y, Position.z,_    '' camera pos
			   Target.x, Target.y, Target.z,_     	  '' camera target
               Up.x, Up.y, Up.z)

end sub



sub Camera.Zoom( value as single )

	EyeDistanceFromScreen +=value

end sub
	

''*****************************************************************************
sub main()
	
	
	dim as integer Frame = 0
	 
	dim as Camera Cam
	dim as Player Mario
	 
	GL_Screen_Init( SCREEN_WIDTH, SCREEN_HEIGHT )   ''Set up GL screen

	
	do
		
		Frame += 1

		Mario.DoStuff()     '' Do player movements
    
		Mario.CollideOnMap( Map() )		'' Do collisions in 2D
		
		
		'' Zoom if you want
		if( multikey(FB.SC_F2) ) then Cam.Zoom(1.62)
		if( multikey(FB.SC_F3) ) then Cam.Zoom(-1.62)
		
		
		
		glMatrixMode( GL_MODELVIEW )
		glLoadIdentity() 
		glPolygonMode( GL_FRONT, GL_FILL )
		glPolygonMode( GL_BACK, GL_FILL )
		glEnable( GL_DEPTH_TEST )
		glDepthFunc( GL_LEQUAL )
		
		glDisable( GL_TEXTURE_2D )
	
		
		glColor4ub( 255, 255, 255, 255 )

		'' Move cam according to player's pos
		'Cam.Follow( Mario.x, Mario.y )
		Cam.Follow( Mario.x, Mario.y,  sgn(Mario.xv)  )
		
		'' reverse y direction for oldskool coords(Easy GL2D = happy)
		glScalef( 1, -1, 1 )
		
		'' Look
		Cam.Look()
		
		'' Clear screen
		glClear(GL_COLOR_BUFFER_BIT OR GL_DEPTH_BUFFER_BIT)

		'' Draw 3D stuff
		glPushMatrix()   
					
			DrawMap()
			Mario.Draw3D()

		glPopMatrix()    
		
		'' limit FPS
		dim as single TimeStart = timer
		while( (timer - TimeStart) < (1.0/60.0) )
			sleep 1,1
		wend
		
		
		flip
		
	Loop until multikey(FB.SC_ESCAPE)

	
	
End Sub



main()


end








''*****************************************************************************
'' Temp way to draw our 32x32 tiles
sub DrawCube( x as single, y as single, z as single, Size as single, Red as single, Green as single, Blue as single )

	glColor4f( Red, Green, Blue, 1 )
	
	glPushMatrix()
		glTranslatef( x + Size, y + Size, z)  '' Offset by Size so that we draw from top-left at (0,0)
	
		glBegin(GL_QUADS)
			'' Front Face
			glColor3f( 1, 0, 0)
			glVertex3f(-Size, -Size,  Size)
			glColor3f( 0, 1, 0)
			glVertex3f( Size, -Size,  Size)
			glColor3f( 0, 0, 1)
			glVertex3f( Size,  Size,  Size)
			glColor3f( 1, 1, 1)
			glVertex3f(-Size,  Size,  Size)
			
			glColor4f( 1, 1, 0, 1 )
	
			'' Back Face
			glVertex3f(-Size, -Size, -Size)
			glVertex3f(-Size,  Size, -Size)
			glVertex3f( Size,  Size, -Size)
			glVertex3f( Size, -Size, -Size)
			'' Top Face
			glVertex3f(-Size,  Size, -Size)
			glVertex3f(-Size,  Size,  Size)
			glVertex3f( Size,  Size,  Size)
			glVertex3f( Size,  Size, -Size)
			'' Bottom Face
			glVertex3f(-Size, -Size, -Size)
			glVertex3f( Size, -Size, -Size)
			glVertex3f( Size, -Size,  Size)
			glVertex3f(-Size, -Size,  Size)
			'' Right face
			glVertex3f( Size, -Size, -Size)
			glVertex3f( Size,  Size, -Size)
			glVertex3f( Size,  Size,  Size)
			glVertex3f( Size, -Size,  Size)
			'' Left Face
			glVertex3f(-Size, -Size, -Size)
			glVertex3f(-Size, -Size,  Size)
			glVertex3f(-Size,  Size,  Size)
			glVertex3f(-Size,  Size, -Size)
		glEnd()
	
	glPopMatrix()
	
	glColor4f( 1, 1, 1, 1 )
	
	
end sub


'' Draws the map in 3D
sub DrawMap()

	for y as integer = 0 to (MAP_HEI - 1)
		for x as integer = 0 to (MAP_WID - 1)
			if( Map(x,y) > 0 ) then			
				DrawCube( x * TILE_SIZE, y * TILE_SIZE, 0, TILE_SIZE/2, 0, 1, 0 )
			end if
		next x	
	next y
	
end sub


''=============================================================================
''
''    Sets up OpenGL for 2d mode
''
''=============================================================================
sub GL_Screen_Init(byval screen_wid as integer, byval screen_hei as integer, byval flags as integer = 0)
	
	if flags then
		screenres screen_wid, screen_hei, 32, 2, FB.GFX_OPENGL or flags
	else
		screenres screen_wid, screen_hei, 32, 2, FB.GFX_OPENGL
	endif
	
	
	'screen information 
	dim w as integer, h as integer 
	'OpenGL params for gluerspective 
	dim FOVy as double            'Field of view angle in Y 
	dim Aspect as double          'Aspect of screen 
	dim znear as double           'z-near clip distance 
	dim zfar as double            'z-far clip distance 

	'using screen info w and h as params 
	glViewport(0, 0, screen_wid, screen_hei)
	
	'Set current Mode to projection(ie: 3d) 
	glMatrixMode(GL_PROJECTION) 
	
	'Load identity matrix to projection matrix 
	glLoadIdentity() 

	'Set gluPerspective params 
	FOVy = 90/2                                     '45 deg fovy 
	Aspect = screen_wid / screen_hei
	znear = 1                                       'Near clip 
	zfar = 1500                                     'far clip 
	
	'use glu Perspective to set our 3d frustum dimension up 
	gluPerspective(FOVy, aspect, znear, zfar) 
	
	'Modelview mode 
	'ie. Matrix that does things to anything we draw 
	'as in lines, points, tris, etc. 
	glMatrixMode(GL_MODELVIEW) 
	'load identity(clean) matrix to modelview 
	glLoadIdentity() 
	
	glShadeModel(GL_SMOOTH)                 'set shading to smooth(try GL_FLAT) 
	glClearColor(0.0, 0.0, 0.0, 1.0)        'set Clear color to BLACK 
	glClearDepth(1.0)                       'Set Depth buffer to 1(z-Buffer) 
	glEnable(GL_DEPTH_TEST)                 'Enable Depth Testing so that our z-buffer works 
	
	'compare each incoming pixel z value with the z value present in the depth buffer 
	'LEQUAL means than pixel is drawn if the incoming z value is less than 
	'or equal to the stored z value 
	glDepthFunc(GL_LEQUAL) 
	
	'have one or more material parameters track the current color 
	'Material is your 3d model 
	glEnable(GL_COLOR_MATERIAL) 


    'Enable Texturing 
    glEnable(GL_TEXTURE_2D) 
    

   	'Tell openGL that we want the best possible perspective transform 
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST) 
	
	'Disable Backface culling
	glDisable (GL_CULL_FACE)
	
	glPolygonMode(GL_FRONT, GL_FILL) 
	
	'' enable blending for transparency 
	glEnable(GL_BLEND)    	    
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
	
	glDisable( GL_DEPTH_TEST )
	
	glEnable( GL_ALPHA_TEST )
	glAlphaFunc(GL_GREATER, 0)


	glDisable(GL_STENCIL_TEST)
	glDisable(GL_TEXTURE_1D)
	glDisable(GL_LIGHTING)
	glDisable(GL_LOGIC_OP)
	glDisable(GL_DITHER)
	glDisable(GL_FOG)

	glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST)
	glHint(GL_LINE_SMOOTH_HINT , GL_FASTEST)

	glPointSize( 1 )
	glLineWidth( 1 )
	
	
end sub



Here's a zip with all the samples:
http://rel.phatcode.net/junk.php?id=123

Here's the DS version:
http://rel.phatcode.net/junk.php?id=122
Last edited by relsoft on Aug 27, 2012 6:50, edited 2 times in total.
relsoft
Posts: 1767
Joined: May 27, 2005 10:34
Location: Philippines
Contact:

Re: The easiest way to code a 3d Platformer.

Post by relsoft »

3. Scrolling with selective tile drawing(very fast)

Code: Select all

''*****************************************************************************
'' 
''   2.5D Engine (Scrolling ala Super Mario)
''   Optimized draw
''   Only draws one screen worth of 3d tiles
''   See "DrawMap()" function for more details
''   Zoom out to see the optimization in action
''
''   Relminator (Richard Eric M. Lope)
''	 http://rel.phatcode.net
''
''	 This is probably the easiest way to make a 3d game
''   Features:
''   * 1:1 ratio of 3D coords to Screen
''   * Collisions are in tilebased 2D
''   * Rendering can be camera based (uber fast)
''   * Any 2D tilebased game can be converted to this
''
''   Controls
''   
''   SPACE = Jump
''   ARROW KEYS = Move
''   F1 = Paper mario mode?
''   F2/F3 = Zoom
''
''*****************************************************************************

#include once "fbgfx.bi"
#include once "/gl/gl.bi" 
#include once "/gl/glu.bi"   


''*****************************************************************************
declare sub GL_Screen_Init(byval screen_wid as integer, byval screen_hei as integer, byval flags as integer = 0)

'' Drawing stuff
''*****************************************************************************
declare sub DrawCube( x as single, y as single, z as single, Size as single, Red as single, Green as single, Blue as single ) 
declare sub DrawMap( byval PlayerX as single, byval PlayerY as single )


''*****************************************************************************
const as integer SCREEN_WIDTH = 640
const as integer SCREEN_HEIGHT = 480

const as integer TILE_SIZE = 32


const as integer MAP_WID = (SCREEN_WIDTH\TILE_SIZE) * 4 '' 20 * 4 worth of tiles
const as integer MAP_HEI = SCREEN_HEIGHT\TILE_SIZE      '' 15

const as integer FALSE = 0
const as integer TRUE = not FALSE

const as single Gravity = 0.75
const as single JumpHeight = 15


''*****************************************************************************
dim shared as integer Map(MAP_WID-1,MAP_HEI-1) =>_
{{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},_  ''1
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''2
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''3
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''4
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''5
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},_   ''6
{1,0,0,0,0,0,0,0,0,0,1,0,0,0,1},_   ''7
{1,0,0,0,0,0,0,1,0,0,1,0,0,0,1},_   ''8
{1,0,0,0,0,1,0,0,0,0,0,0,0,0,1},_   ''9
{1,0,0,0,0,0,0,0,0,0,0,0,1,0,1},_   ''10
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''11
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''12
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},_   ''13
{1,0,0,0,0,0,1,0,0,0,0,0,1,0,1},_   ''14
{1,0,0,0,0,0,0,0,0,0,0,1,0,0,1},_   ''15
{1,0,0,0,0,0,1,0,0,0,0,1,0,0,1},_   ''16
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''17
{1,0,0,0,0,1,0,0,0,0,0,0,0,0,1},_   ''18
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},_   ''19
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},_   ''19
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},_   ''19
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''2
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''3
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''4
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''5
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},_   ''6
{1,0,0,0,0,0,0,0,0,0,1,0,0,0,1},_   ''7
{1,0,0,0,0,0,0,1,0,0,1,0,0,0,1},_   ''8
{1,0,0,0,0,1,0,0,0,0,0,0,0,0,1},_   ''9
{1,0,0,0,0,0,0,0,0,0,0,0,1,0,1},_   ''10
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''11
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''12
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},_   ''13
{1,0,0,0,0,0,1,0,0,0,0,0,1,0,1},_   ''14
{1,0,0,0,0,0,0,0,0,0,0,1,0,0,1},_   ''15
{1,0,0,0,0,0,1,0,0,0,0,1,0,0,1},_   ''16
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''17
{1,0,0,0,0,1,0,0,0,0,0,0,0,0,1},_   ''18
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},_   ''19
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},_   ''19
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},_   ''19
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''2
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''3
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''4
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''5
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},_   ''6
{1,0,0,0,0,0,0,0,0,0,1,0,0,0,1},_   ''7
{1,0,0,0,0,0,0,1,0,0,1,0,0,0,1},_   ''8
{1,0,0,0,0,1,0,0,0,0,0,0,0,0,1},_   ''9
{1,0,0,0,0,0,0,0,0,0,0,0,1,0,1},_   ''10
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''11
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''12
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},_   ''13
{1,0,0,0,0,0,1,0,0,0,0,0,1,0,1},_   ''14
{1,0,0,0,0,0,0,0,0,0,0,1,0,0,1},_   ''15
{1,0,0,0,0,0,1,0,0,0,0,1,0,0,1},_   ''16
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''17
{1,0,0,0,0,1,0,0,0,0,0,0,0,0,1},_   ''18
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},_   ''19
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},_   ''19
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},_   ''19
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''2
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''3
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''4
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''5
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},_   ''6
{1,0,0,0,0,0,0,0,0,0,1,0,0,0,1},_   ''7
{1,0,0,0,0,0,0,1,0,0,1,0,0,0,1},_   ''8
{1,0,0,0,0,1,0,0,0,0,0,0,0,0,1},_   ''9
{1,0,0,0,0,0,0,0,0,0,0,0,1,0,1},_   ''10
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''11
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''12
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},_   ''13
{1,0,0,0,0,0,1,0,0,0,0,0,1,0,1},_   ''14
{1,0,0,0,0,0,0,0,0,0,0,1,0,0,1},_   ''15
{1,0,0,0,0,0,1,0,0,0,0,1,0,0,1},_   ''16
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''17
{1,0,0,0,0,1,0,0,0,0,0,0,0,0,1},_   ''18
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},_   ''19
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}}


''*****************************************************************************
''
''
''
''*****************************************************************************
type Player

	x		as single
	y		as single
	speed	as single
	xv		as single
	yv		as single
	wid		as integer
	hei		as integer
	
	CanJump  as integer
	
	declare constructor()
	declare function CollideFloors(byval ix as integer, byval iy as integer, byref TileY as integer, Map() as integer ) as integer
	declare function CollideWalls(byval ix as integer, byval iy as integer, byref TileX as integer, Map() as integer ) as integer
	declare sub DoStuff()
	declare sub CollideOnMap( Map() as integer )
	declare sub Draw3D()
	
end type

constructor Player()
	x = 32 * 2 
	y = 32 * 5 
	speed = 4.5
	wid = 24
	hei = 48
	CanJump = false
End Constructor



function Player.CollideWalls(byval ix as integer, byval iy as integer, byref TileX as integer, Map() as integer ) as integer
	
	dim as integer TileYpixels = iy - (iy mod TILE_SIZE)   '' Pixel of the player's head snapped to map grid
	dim as integer TestEnd = iy + hei					   '' Foot of the player
	
	TileX = ix\TILE_SIZE								   '' Current X map coord the player is on + x-velocity(+ width when moving right)
	
	dim as integer TileY = TileYpixels\TILE_SIZE		   '' Current Y map coord of the player's head
	
	'' Scan downwards from head to foot if we collided with a tile on the right or left
	while (TileYpixels <= TestEnd)
		if (Map(TileX, TileY))	then return true		   '' Found a tile

		TileY += 1										   '' Next tile downward
		TileYpixels +=TILE_SIZE							   '' Next tile pixel downward
		
	Wend
	
	return false
End Function

function Player.CollideFloors(byval ix as integer, byval iy as integer, byref TileY as integer, Map() as integer ) as integer
	
	dim as integer TileXpixels = ix - (ix mod TILE_SIZE)
	dim as integer TestEnd = ix + wid
	
	TileY = iy\TILE_SIZE
	
	dim as integer TileX = TileXpixels\TILE_SIZE
	
	while (TileXpixels <= TestEnd)
		if (Map(TileX, TileY))	then return true	

		TileX += 1
		TileXpixels +=TILE_SIZE
		
	Wend
	
	return false
End Function



sub Player.DoStuff()

	xv = 0
	
	if multikey(FB.SC_LEFT) then 
		xv = -speed
	EndIf
	
    if multikey(FB.SC_RIGHT) then 
    	xv = speed
    EndIf
    
    if multikey(FB.SC_SPACE) then 
	    if( CanJump ) then
	    	yv = -JumpHeight
	    	CanJump = false
	    end if
    EndIf
    
    
    
End Sub

sub Player.CollideOnMap( Map() as integer )
	
	dim as Integer TileX, TileY

	if( xv > 0 ) then
		
		if( CollideWalls( x + xv + wid, y, TileX, Map() ) ) then
			x = TileX * TILE_SIZE - wid - 1
		else
			x += xv
		EndIf
			
	elseif( xv < 0 ) then
		
		if( CollideWalls( x + xv, y, TileX, Map() ) ) then
			x = ( TileX + 1 ) * TILE_SIZE + 1
		else
			x += xv
		EndIf
		
	EndIf
	
	if( yv < 0 ) then
		
		if( CollideFloors( x, y + yv, TileY, Map() ) ) then   '' hit the roof
			y = ( TileY + 1 ) * TILE_SIZE + 1
			yv = 0    
		else
			y += yv
			yv += Gravity
		EndIf
			
	else
		
		if( CollideFloors( x, y + yv + hei, TileY, Map() ) ) then
			y = ( TileY ) * TILE_SIZE - hei - 1
			yv = 1
			if not multikey(FB.SC_SPACE) then CanJump = true
		else
			y += yv
			yv += Gravity
			CanJump = false
		EndIf
		
	EndIf
	
	
End Sub


sub Player.Draw3D()

	'' Draws the player in 3D	
	dim as single SizeX = Wid/2.0
	dim as single SizeY = Hei/2.0
	
	
	glColor4f( 1, 0, 1, 1 )
	glPushMatrix()
		glTranslatef( x + Wid/2, y + Hei/2.0, 0) '' Offset by Size/2 so that we draw from top-left at (0,0)
		glBegin(GL_QUADS)
			glVertex3f(-SizeX, -SizeY,  0)
			glVertex3f( SizeX, -SizeY,  0)
			glVertex3f( SizeX,  SizeY,  0)
			glVertex3f(-SizeX,  SizeY,  0)			
		glEnd()
	glPopMatrix()
	
	
end sub

	
''*****************************************************************************
''
''
''
''*****************************************************************************

Type Vector2D

	x as Single
	y as Single
	z as single
	
end type

Type Camera
	
	
	declare Constructor()
	declare sub Follow( x as single, y as single )
	declare sub Follow( x as single, y as single, skew as integer )
	declare sub Look()
	declare sub Look( value as single )
	declare sub Zoom( value as single )

	
	
	Position as Vector2D 
	Target as Vector2D 
	Up as Vector2D 
	
	EyeDistanceFromScreen as integer

end type


constructor Camera()

	EyeDistanceFromScreen = TILE_SIZE * 15   '' Distance of player's eye from screen
	
	Position.x = 0
	Position.y = 0
	Position.z = EyeDistanceFromScreen       '' Yep we are drawing at z = 0 so pos should be positive
	
	Target.x = 0
	Target.y = 0
	Target.z = 0
	
	Up.x = 0
	Up.y = 1
	Up.z = 0
	
	
end constructor	

sub Camera.Follow( x as single, y as single )

	
	Position.x = x
	Position.y = y - TILE_SIZE * 1    		'' offset a little above so we look a little down
	Position.z = EyeDistanceFromScreen      '' move zpos n units from screen to eye
	
	Target.x = x
	Target.y = y
	Target.z = 0
	
	Up.x = 0
	Up.y = 1
	Up.z = 0
	
end sub

sub Camera.Follow( x as single, y as single, skew as integer )

	static as single rot = 0
	if( skew > 0 ) then
		if( rot < 100 ) then rot += 5  
	elseif ( skew < 0 ) then
		if( rot > -100 ) then rot -= 5
	else  '' 0
		if( rot > 0 ) then rot -= 5
		if( rot < 0 ) then rot += 5
	end if
	
	Position.x = x - rot 
	Position.y = y - TILE_SIZE * 1    		'' offset a little above so we look a little down
	Position.z = EyeDistanceFromScreen      '' move zpos n units from screen to eye
	
	Target.x = x + rot
	Target.y = y
	Target.z = 0
	
	Up.x = 0
	Up.y = 1
	Up.z = 0
	
end sub



sub Camera.Look()

	
	gluLookAt( Position.x, Position.y, Position.z,_    '' camera pos
			   Target.x, Target.y, Target.z,_     	  '' camera target
               Up.x, Up.y, Up.z)

end sub



sub Camera.Zoom( value as single )

	EyeDistanceFromScreen +=value

end sub
	

''*****************************************************************************
sub main()
	
	
	dim as integer Frame = 0
	 
	dim as Camera Cam
	dim as Player Mario
	 
	GL_Screen_Init( SCREEN_WIDTH, SCREEN_HEIGHT )   ''Set up GL screen

	
	do
		
		Frame += 1

		Mario.DoStuff()     '' Do player movements
    
		Mario.CollideOnMap( Map() )		'' Do collisions in 2D
		
		
		'' Zoom if you want
		if( multikey(FB.SC_F2) ) then Cam.Zoom(1.62)
		if( multikey(FB.SC_F3) ) then Cam.Zoom(-1.62)
		
		
		
		glMatrixMode( GL_MODELVIEW )
		glLoadIdentity() 
		glPolygonMode( GL_FRONT, GL_FILL )
		glPolygonMode( GL_BACK, GL_FILL )
		glEnable( GL_DEPTH_TEST )
		glDepthFunc( GL_LEQUAL )
		
		glDisable( GL_TEXTURE_2D )
	
		
		glColor4ub( 255, 255, 255, 255 )

		'' Move cam according to player's pos
		Cam.Follow( Mario.x, Mario.y )
		
		'' reverse y direction for oldskool coords(Easy GL2D = happy)
		glScalef( 1, -1, 1 )
		
		'' Look
		Cam.Look()
		
		'' Paper mario?
		if( multikey(FB.SC_F1) ) then glRotatef( 20, 0, 1, 0 )
		
		'' Clear screen
		glClear(GL_COLOR_BUFFER_BIT OR GL_DEPTH_BUFFER_BIT)

		'' Draw 3D stuff
		glPushMatrix()   
					
			DrawMap( Mario.x, Mario.y )
			Mario.Draw3D()

		glPopMatrix()    
		
		'' limit FPS
		dim as single TimeStart = timer
		while( (timer - TimeStart) < (1.0/60.0) )
			sleep 1,1
		wend
		
		
		flip
		
	Loop until multikey(FB.SC_ESCAPE)

	
	
End Sub



main()


end








''*****************************************************************************
'' Temp way to draw our 32x32 tiles
sub DrawCube( x as single, y as single, z as single, Size as single, Red as single, Green as single, Blue as single )

	glColor4f( Red, Green, Blue, 1 )
	
	glPushMatrix()
		glTranslatef( x + Size, y + Size, z)  '' Offset by Size so that we draw from top-left at (0,0)
	
		glBegin(GL_QUADS)
			'' Front Face
			glColor3f( 1, 0, 0)
			glVertex3f(-Size, -Size,  Size)
			glColor3f( 0, 1, 0)
			glVertex3f( Size, -Size,  Size)
			glColor3f( 0, 0, 1)
			glVertex3f( Size,  Size,  Size)
			glColor3f( 1, 1, 1)
			glVertex3f(-Size,  Size,  Size)
			
			glColor4f( 1, 1, 0, 1 )
	
			'' Back Face
			glVertex3f(-Size, -Size, -Size)
			glVertex3f(-Size,  Size, -Size)
			glVertex3f( Size,  Size, -Size)
			glVertex3f( Size, -Size, -Size)
			'' Top Face
			glVertex3f(-Size,  Size, -Size)
			glVertex3f(-Size,  Size,  Size)
			glVertex3f( Size,  Size,  Size)
			glVertex3f( Size,  Size, -Size)
			'' Bottom Face
			glVertex3f(-Size, -Size, -Size)
			glVertex3f( Size, -Size, -Size)
			glVertex3f( Size, -Size,  Size)
			glVertex3f(-Size, -Size,  Size)
			'' Right face
			glVertex3f( Size, -Size, -Size)
			glVertex3f( Size,  Size, -Size)
			glVertex3f( Size,  Size,  Size)
			glVertex3f( Size, -Size,  Size)
			'' Left Face
			glVertex3f(-Size, -Size, -Size)
			glVertex3f(-Size, -Size,  Size)
			glVertex3f(-Size,  Size,  Size)
			glVertex3f(-Size,  Size, -Size)
		glEnd()
	
	glPopMatrix()
	
	glColor4f( 1, 1, 1, 1 )
	
	
end sub


'' Draws the map in 3D
'' Fast selective tile drawing
sub DrawMap( byval PlayerX as single, byval PlayerY as single )
	
	'' Number of Tiles we draw at one time ( Just a screenfull of it)
	const as integer ScreenTilesX = SCREEN_WIDTH \ TILE_SIZE
	const as integer ScreenTilesY = SCREEN_HEIGHT \ TILE_SIZE
	
	'' Starting tiles = (Player - Halfscreen) \ TileSize
	dim as integer TileX = ( PlayerX - SCREEN_WIDTH \ 2 ) \ TILE_SIZE
	dim as integer TileY = ( PlayerY - SCREEN_HEIGHT \ 2 ) \ TILE_SIZE
	
	'' Limit left-top
	if( TileX < 0 ) then TileX = 0
	if( TileY < 0 ) then TileY = 0
	
	'' Limit right = (Player - Halfscreen) \ TileSize
	dim as integer MaxX = MAP_WID - (SCREEN_WIDTH\TILE_SIZE) 
	if( TileX > MaxX ) then TileX = MaxX
	
	'' Limit bottom
	dim as integer MaxY = MAP_HEI - (SCREEN_HEIGHT\TILE_SIZE) 
	if( TileY > MaxY ) then TileY = MaxY
	
	'' Draw
	for y as integer = TileY to  (TileY + (ScreenTilesY - 1))
		for x as integer = TileX to (TileX + (ScreenTilesX - 1))
			if( Map(x,y) > 0 ) then			
				DrawCube( x * TILE_SIZE, y * TILE_SIZE, 0, TILE_SIZE/2, 0, 1, 0 )
			end if
		next x	
	next y
	
end sub


''=============================================================================
''
''    Sets up OpenGL for 2d mode
''
''=============================================================================
sub GL_Screen_Init(byval screen_wid as integer, byval screen_hei as integer, byval flags as integer = 0)
	
	if flags then
		screenres screen_wid, screen_hei, 32, 2, FB.GFX_OPENGL or flags
	else
		screenres screen_wid, screen_hei, 32, 2, FB.GFX_OPENGL
	endif
	
	
	'screen information 
	dim w as integer, h as integer 
	'OpenGL params for gluerspective 
	dim FOVy as double            'Field of view angle in Y 
	dim Aspect as double          'Aspect of screen 
	dim znear as double           'z-near clip distance 
	dim zfar as double            'z-far clip distance 

	'using screen info w and h as params 
	glViewport(0, 0, screen_wid, screen_hei)
	
	'Set current Mode to projection(ie: 3d) 
	glMatrixMode(GL_PROJECTION) 
	
	'Load identity matrix to projection matrix 
	glLoadIdentity() 

	'Set gluPerspective params 
	FOVy = 90/2                                     '45 deg fovy 
	Aspect = screen_wid / screen_hei
	znear = 1                                       'Near clip 
	zfar = 1500                                     'far clip 
	
	'use glu Perspective to set our 3d frustum dimension up 
	gluPerspective(FOVy, aspect, znear, zfar) 
	
	'Modelview mode 
	'ie. Matrix that does things to anything we draw 
	'as in lines, points, tris, etc. 
	glMatrixMode(GL_MODELVIEW) 
	'load identity(clean) matrix to modelview 
	glLoadIdentity() 
	
	glShadeModel(GL_SMOOTH)                 'set shading to smooth(try GL_FLAT) 
	glClearColor(0.0, 0.0, 0.0, 1.0)        'set Clear color to BLACK 
	glClearDepth(1.0)                       'Set Depth buffer to 1(z-Buffer) 
	glEnable(GL_DEPTH_TEST)                 'Enable Depth Testing so that our z-buffer works 
	
	'compare each incoming pixel z value with the z value present in the depth buffer 
	'LEQUAL means than pixel is drawn if the incoming z value is less than 
	'or equal to the stored z value 
	glDepthFunc(GL_LEQUAL) 
	
	'have one or more material parameters track the current color 
	'Material is your 3d model 
	glEnable(GL_COLOR_MATERIAL) 


    'Enable Texturing 
    glEnable(GL_TEXTURE_2D) 
    

   	'Tell openGL that we want the best possible perspective transform 
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST) 
	
	'Disable Backface culling
	glDisable (GL_CULL_FACE)
	
	glPolygonMode(GL_FRONT, GL_FILL) 
	
	'' enable blending for transparency 
	glEnable(GL_BLEND)    	    
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
	
	glDisable( GL_DEPTH_TEST )
	
	glEnable( GL_ALPHA_TEST )
	glAlphaFunc(GL_GREATER, 0)


	glDisable(GL_STENCIL_TEST)
	glDisable(GL_TEXTURE_1D)
	glDisable(GL_LIGHTING)
	glDisable(GL_LOGIC_OP)
	glDisable(GL_DITHER)
	glDisable(GL_FOG)

	glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST)
	glHint(GL_LINE_SMOOTH_HINT , GL_FASTEST)

	glPointSize( 1 )
	glLineWidth( 1 )
	
	
end sub




4. Delta time version (I know Lachie will like this)

Code: Select all

''*****************************************************************************
'' 
''   2.5D Engine (DeltaTime Version )
''   Relminator (Richard Eric M. Lope)
''	 http://rel.phatcode.net
''
''	 This is probably the easiest way to make a 3d game
''   Features:
''   * 1:1 ratio of 3D coords to Screen
''   * Collisions are in tilebased 2D
''   * Rendering can be camera based (uber fast)
''   * Any 2D tilebased game can be converted to this
''
''   Controls
''   
''   SPACE = Jump
''   ARROW KEYS = Move
''   F1 = Paper mario mode?
''   F2/F3 = Zoom
''
''*****************************************************************************

#include once "fbgfx.bi"
#include once "/gl/gl.bi" 
#include once "/gl/glu.bi"   


declare function GetDeltaTime( byref FPS as single, byval TimerInSeconds as single) as single


''*****************************************************************************
declare sub GL_Screen_Init(byval screen_wid as integer, byval screen_hei as integer, byval flags as integer = 0)

'' Drawing stuff
''*****************************************************************************
declare sub DrawCube( x as single, y as single, z as single, Size as single, Red as single, Green as single, Blue as single ) 
declare sub DrawMap()


''*****************************************************************************
const as integer SCREEN_WIDTH = 640
const as integer SCREEN_HEIGHT = 480

const as integer TILE_SIZE = 32


const as integer MAP_WID = SCREEN_WIDTH\TILE_SIZE      '' 20
const as integer MAP_HEI = SCREEN_HEIGHT\TILE_SIZE      '' 15

const as integer FALSE = 0
const as integer TRUE = not FALSE

const as single Gravity = 1400   '' 35 pixels a second
const as single JumpHeight = 600


''*****************************************************************************
dim shared as integer Map(MAP_WID-1,MAP_HEI-1) =>_
{{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},_  ''1
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''2
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''3
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''4
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''5
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},_   ''6
{1,0,0,0,0,0,0,0,0,0,1,0,0,0,1},_   ''7
{1,0,0,0,0,0,0,1,0,0,1,0,0,0,1},_   ''8
{1,0,0,0,0,1,0,0,0,0,0,0,0,0,1},_   ''9
{1,0,0,0,0,0,0,0,0,0,0,0,1,0,1},_   ''10
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''11
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''12
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},_   ''13
{1,0,0,0,0,0,1,0,0,0,0,0,1,0,1},_   ''14
{1,0,0,0,0,0,0,0,0,0,0,1,0,0,1},_   ''15
{1,0,0,0,0,0,1,0,0,0,0,1,0,0,1},_   ''16
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''17
{1,0,0,0,0,1,0,0,0,0,0,0,0,0,1},_   ''18
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},_   ''19
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}}


''*****************************************************************************
''
''
''
''*****************************************************************************
type Player

	x		as single
	y		as single
	speed	as single
	xv		as single
	yv		as single
	wid		as integer
	hei		as integer
	
	CanJump as Integer
	
	declare constructor()
	declare function CollideFloors(byval ix as integer, byval iy as integer, byref TileY as integer, Map() as integer ) as integer
	declare function CollideWalls(byval ix as integer, byval iy as integer, byref TileX as integer, Map() as integer ) as integer
	declare sub DoStuff( byval dt as single )
	declare sub CollideOnMap( Map() as integer, byval dt as single )
	declare sub Draw3D()
	
end type

constructor Player()

	x = 32 * 2 
	y = 32 * 5 
	speed = 180   '' pixels a second
	wid = 24
	hei = 48
	CanJump = false
	
End Constructor



function Player.CollideWalls(byval ix as integer, byval iy as integer, byref TileX as integer, Map() as integer ) as integer
	
	dim as integer TileYpixels = iy - (iy mod TILE_SIZE)   '' Pixel of the player's head snapped to map grid
	dim as integer TestEnd = iy + hei					   '' Foot of the player
	
	TileX = ix\TILE_SIZE								   '' Current X map coord the player is on + x-velocity(+ width when moving right)
	
	dim as integer TileY = TileYpixels\TILE_SIZE		   '' Current Y map coord of the player's head
	
	'' Scan downwards from head to foot if we collided with a tile on the right or left
	while (TileYpixels <= TestEnd)
		if (Map(TileX, TileY))	then return true		   '' Found a tile

		TileY += 1										   '' Next tile downward
		TileYpixels +=TILE_SIZE							   '' Next tile pixel downward
		
	Wend
	
	return false
End Function

function Player.CollideFloors(byval ix as integer, byval iy as integer, byref TileY as integer, Map() as integer ) as integer
	
	dim as integer TileXpixels = ix - (ix mod TILE_SIZE)
	dim as integer TestEnd = ix + wid
	
	TileY = iy\TILE_SIZE
	
	dim as integer TileX = TileXpixels\TILE_SIZE
	
	while (TileXpixels <= TestEnd)
		if (Map(TileX, TileY))	then return true	

		TileX += 1
		TileXpixels +=TILE_SIZE
		
	Wend
	
	return false
End Function



sub Player.DoStuff( byval dt as single )

	xv = 0
	
	if multikey(FB.SC_LEFT) then 
		xv = -speed * dt
	EndIf
	
    if multikey(FB.SC_RIGHT) then 
    	xv = speed * dt
    EndIf
    
    if multikey(FB.SC_SPACE) then 
	    if( CanJump ) then
	    	yv = -JumpHeight
	    	CanJump = false
	    end if
    EndIf
    
    
    
End Sub

sub Player.CollideOnMap( Map() as integer, byval dt as single  )
	
	dim as Integer TileX, TileY
	
	if( xv > 0 ) then
		
		if( CollideWalls( x + xv + wid, y, TileX, Map() ) ) then
			x = TileX * TILE_SIZE - wid - 1
		else
			x += xv
		EndIf
			
	elseif( xv < 0 ) then
		
		if( CollideWalls( x + xv, y, TileX, Map() ) ) then
			x = ( TileX + 1 ) * TILE_SIZE + 1
		else
			x += xv
		EndIf
		
	EndIf
	
	if( yv < 0 ) then
		
		if( CollideFloors( x, y + (yv * dt), TileY, Map() ) ) then   '' hit the roof
			y = ( TileY + 1 ) * TILE_SIZE + 1
			yv = 0    
		else
			y += yv * dt
			yv += Gravity * dt
		EndIf
			
	else
		
		if( CollideFloors( x, y + (yv * dt) + hei, TileY, Map() ) ) then   '' hit the floor
			y = ( TileY ) * TILE_SIZE - hei - 1
			yv = 150   '' bigger values
			if multikey(FB.SC_SPACE) then CanJump = true
		else
			y += yv * dt
			yv += Gravity * dt
			CanJump = false
		EndIf
		
	EndIf
	
	
End Sub


sub Player.Draw3D()

	'' Draws the player in 3D	
	dim as single SizeX = Wid/2.0
	dim as single SizeY = Hei/2.0
	
	
	glColor4f( 1, 0, 1, 1 )
	glPushMatrix()
		glTranslatef( x + Wid/2, y + Hei/2.0, 0) '' Offset by Size/2 so that we draw from top-left at (0,0)
		glBegin(GL_QUADS)
			glVertex3f(-SizeX, -SizeY,  0)
			glVertex3f( SizeX, -SizeY,  0)
			glVertex3f( SizeX,  SizeY,  0)
			glVertex3f(-SizeX,  SizeY,  0)			
		glEnd()
	glPopMatrix()
	
	
end sub

	
''*****************************************************************************
''
''
''
''*****************************************************************************

Type Vector2D

	x as Single
	y as Single
	z as single
	
end type

Type Camera
	
	
	declare Constructor()
	declare sub Follow( x as single, y as single )
	declare sub Look()
	declare sub Look( value as single )
	declare sub Zoom( value as single )

	
	
	Position as Vector2D 
	Target as Vector2D 
	Up as Vector2D 
	
	EyeDistanceFromScreen as integer

end type


constructor Camera()

	EyeDistanceFromScreen = TILE_SIZE * 18   '' Distance of player's eye from screen
	
	Position.x = 0
	Position.y = 0
	Position.z = EyeDistanceFromScreen       '' Yep we are drawing at z = 0 so pos should be positive
	
	Target.x = 0
	Target.y = 0
	Target.z = 0
	
	Up.x = 0
	Up.y = 1
	Up.z = 0
	
	
end constructor	

sub Camera.Follow( x as single, y as single )

	
	Position.x = x
	Position.y = y - TILE_SIZE * 1    		'' offset a little above so we look a little down
	Position.z = EyeDistanceFromScreen      '' move zpos n units from screen to eye
	
	Target.x = x
	Target.y = y
	Target.z = 0
	
	Up.x = 0
	Up.y = 1
	Up.z = 0
	
end sub


sub Camera.Look()

	
	gluLookAt( Position.x, Position.y, Position.z,_    '' camera pos
			   Target.x, Target.y, Target.z,_     	  '' camera target
               Up.x, Up.y, Up.z)

end sub



sub Camera.Zoom( value as single )

	EyeDistanceFromScreen +=value

end sub
	

''*****************************************************************************
sub main()
	
	dim as single FPS
	dim as integer Frame = 0
	
	dim as Camera Cam
	dim as Player Mario
	 
	GL_Screen_Init( SCREEN_WIDTH, SCREEN_HEIGHT )   ''Set up GL screen

	dim as single dt = GetDeltaTime( FPS, Timer )
	
	
	do
		
		Frame += 1

		dt = GetDeltaTime( FPS, Timer )
	
		Mario.DoStuff( dt )     '' Do player movements
    
		Mario.CollideOnMap( Map(), dt )		'' Do collisions in 2D
		
		
		'' Zoom if you want
		if( multikey(FB.SC_F2) ) then Cam.Zoom(1.62)
		if( multikey(FB.SC_F3) ) then Cam.Zoom(-1.62)
		
		
		
		glMatrixMode( GL_MODELVIEW )
		glLoadIdentity() 
		glPolygonMode( GL_FRONT, GL_FILL )
		glPolygonMode( GL_BACK, GL_FILL )
		glEnable( GL_DEPTH_TEST )
		glDepthFunc( GL_LEQUAL )
		
		glDisable( GL_TEXTURE_2D )
	
		
		glColor4ub( 255, 255, 255, 255 )

		'' Move cam according to player's pos
		Cam.Follow( Mario.x, Mario.y )
		
		'' reverse y direction for oldskool coords(Easy GL2D = happy)
		glScalef( 1, -1, 1 )
		
		'' Look
		Cam.Look()
		
		'' Paper mario?
		if( multikey(FB.SC_F1) ) then glRotatef( 20, 0, 1, 0 )
		
		'' Clear screen
		glClear(GL_COLOR_BUFFER_BIT OR GL_DEPTH_BUFFER_BIT)

		'' Draw 3D stuff
		glPushMatrix()   
					
			DrawMap()
			Mario.Draw3D()

		glPopMatrix()    
		
		'screensync	
		flip
		
		sleep 10,1
		
	Loop until multikey(FB.SC_ESCAPE)

	
End Sub



main()


end








''*****************************************************************************
'' Temp way to draw our 32x32 tiles
sub DrawCube( x as single, y as single, z as single, Size as single, Red as single, Green as single, Blue as single )

	glColor4f( Red, Green, Blue, 1 )
	
	glPushMatrix()
		glTranslatef( x + Size, y + Size, z)  '' Offset by Size so that we draw from top-left at (0,0)
		
		glBegin(GL_QUADS)
			'' Front Face
			glColor3f( 1, 0, 0)
			glVertex3f(-Size, -Size,  Size)
			glColor3f( 0, 1, 0)
			glVertex3f( Size, -Size,  Size)
			glColor3f( 0, 0, 1)
			glVertex3f( Size,  Size,  Size)
			glColor3f( 1, 1, 1)
			glVertex3f(-Size,  Size,  Size)
			
			glColor4f( 1, 1, 0, 1 )
	
			'' Back Face
			glVertex3f(-Size, -Size, -Size)
			glVertex3f(-Size,  Size, -Size)
			glVertex3f( Size,  Size, -Size)
			glVertex3f( Size, -Size, -Size)
			'' Top Face
			glVertex3f(-Size,  Size, -Size)
			glVertex3f(-Size,  Size,  Size)
			glVertex3f( Size,  Size,  Size)
			glVertex3f( Size,  Size, -Size)
			'' Bottom Face
			glVertex3f(-Size, -Size, -Size)
			glVertex3f( Size, -Size, -Size)
			glVertex3f( Size, -Size,  Size)
			glVertex3f(-Size, -Size,  Size)
			'' Right face
			glVertex3f( Size, -Size, -Size)
			glVertex3f( Size,  Size, -Size)
			glVertex3f( Size,  Size,  Size)
			glVertex3f( Size, -Size,  Size)
			'' Left Face
			glVertex3f(-Size, -Size, -Size)
			glVertex3f(-Size, -Size,  Size)
			glVertex3f(-Size,  Size,  Size)
			glVertex3f(-Size,  Size, -Size)
		glEnd()
	
	glPopMatrix()
	
	glColor4f( 1, 1, 1, 1 )
	
	
end sub


'' Draws the map in 3D
sub DrawMap()

	for y as integer = 0 to (MAP_HEI - 1)
		for x as integer = 0 to (MAP_WID - 1)
			if( Map(x,y) > 0 ) then			
				DrawCube( x * TILE_SIZE, y * TILE_SIZE, 0, TILE_SIZE/2, 0, 1, 0 )
			end if
		next x	
	next y
	
end sub


''=============================================================================
''
''    Sets up OpenGL for 2d mode
''
''=============================================================================
sub GL_Screen_Init(byval screen_wid as integer, byval screen_hei as integer, byval flags as integer = 0)
	
	if flags then
		screenres screen_wid, screen_hei, 32, 2, FB.GFX_OPENGL or flags
	else
		screenres screen_wid, screen_hei, 32, 2, FB.GFX_OPENGL
	endif
	
	
	'screen information 
	dim w as integer, h as integer 
	'OpenGL params for gluerspective 
	dim FOVy as double            'Field of view angle in Y 
	dim Aspect as double          'Aspect of screen 
	dim znear as double           'z-near clip distance 
	dim zfar as double            'z-far clip distance 

	'using screen info w and h as params 
	glViewport(0, 0, screen_wid, screen_hei)
	
	'Set current Mode to projection(ie: 3d) 
	glMatrixMode(GL_PROJECTION) 
	
	'Load identity matrix to projection matrix 
	glLoadIdentity() 

	'Set gluPerspective params 
	FOVy = 90/2                                     '45 deg fovy 
	Aspect = screen_wid / screen_hei
	znear = 1                                       'Near clip 
	zfar = 1500                                     'far clip 
	
	'use glu Perspective to set our 3d frustum dimension up 
	gluPerspective(FOVy, aspect, znear, zfar) 
	
	'Modelview mode 
	'ie. Matrix that does things to anything we draw 
	'as in lines, points, tris, etc. 
	glMatrixMode(GL_MODELVIEW) 
	'load identity(clean) matrix to modelview 
	glLoadIdentity() 
	
	glShadeModel(GL_SMOOTH)                 'set shading to smooth(try GL_FLAT) 
	glClearColor(0.0, 0.0, 0.0, 1.0)        'set Clear color to BLACK 
	glClearDepth(1.0)                       'Set Depth buffer to 1(z-Buffer) 
	glEnable(GL_DEPTH_TEST)                 'Enable Depth Testing so that our z-buffer works 
	
	'compare each incoming pixel z value with the z value present in the depth buffer 
	'LEQUAL means than pixel is drawn if the incoming z value is less than 
	'or equal to the stored z value 
	glDepthFunc(GL_LEQUAL) 
	
	'have one or more material parameters track the current color 
	'Material is your 3d model 
	glEnable(GL_COLOR_MATERIAL) 


    'Enable Texturing 
    glEnable(GL_TEXTURE_2D) 
    

   	'Tell openGL that we want the best possible perspective transform 
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST) 
	
	'Disable Backface culling
	glDisable (GL_CULL_FACE)
	
	glPolygonMode(GL_FRONT, GL_FILL) 
	
	'' enable blending for transparency 
	glEnable(GL_BLEND)    	    
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
	
	glDisable( GL_DEPTH_TEST )
	
	glEnable( GL_ALPHA_TEST )
	glAlphaFunc(GL_GREATER, 0)


	glDisable(GL_STENCIL_TEST)
	glDisable(GL_TEXTURE_1D)
	glDisable(GL_LIGHTING)
	glDisable(GL_LOGIC_OP)
	glDisable(GL_DITHER)
	glDisable(GL_FOG)

	glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST)
	glHint(GL_LINE_SMOOTH_HINT , GL_FASTEST)

	glPointSize( 1 )
	glLineWidth( 1 )
	
	
end sub



function GetDeltaTime( byref FPS as single, byval TimerInSeconds as single) as single
	
	'' vars to be used in calculating FPS
	static as single FramesPerSecond = 0.0
	static as single PreviousTime = 0 
	
	'' var to save our last time for comparing 
	static as single OldTime = 0.0

	'' Get the current time in seconds
	dim as single CurrentTime = TimerInSeconds             
	
	'' Time interval between frames
	dim as single ElapsedTime = CurrentTime - OldTime
	
	
	'' Save the current time for comparing the next frame time
	OldTime = CurrentTime
	
	'' Increase the frame counter
	FramesPerSecond += 1
	
	'' Calculate FPS
	if( (CurrentTime - PreviousTime) > 1.0  ) then
	 
		'' Save old_time
	    PreviousTime = CurrentTime

		'' duh?		
		FPS = FramesPerSecond
		
		'' Reset the frames counter since 1 second has already elapsed
	    FramesPerSecond = 0
	end if  
	
	return ElapsedTime
	
end function

Last edited by relsoft on Aug 17, 2012 2:40, edited 1 time in total.
relsoft
Posts: 1767
Joined: May 27, 2005 10:34
Location: Philippines
Contact:

Re: The easiest way to code a 3d Platformer.

Post by relsoft »

5. Fixed cam for puzzlers

Code: Select all

''*****************************************************************************
'' 
''   2.5D Engine (Fixed Camera)
''   Relminator (Richard Eric M. Lope)
''	 http://rel.phatcode.net
''
''	 This is probably the easiest way to make a 3d game
''   Features:
''   * 1:1 ratio of 3D coords to Screen
''   * Collisions are in tilebased 2D
''   * Rendering can be camera based (uber fast)
''   * Any 2D tilebased game can be converted to this
''
''   Controls
''   
''   SPACE = Jump
''   ARROW KEYS = Move
''   F1 = Paper mario mode?
''   F2/F3 = Zoom
''
''*****************************************************************************

#include once "fbgfx.bi"
#include once "/gl/gl.bi" 
#include once "/gl/glu.bi"   


''*****************************************************************************
declare sub GL_Screen_Init(byval screen_wid as integer, byval screen_hei as integer, byval flags as integer = 0)

'' Drawing stuff
''*****************************************************************************
declare sub DrawCube( x as single, y as single, z as single, Size as single, Red as single, Green as single, Blue as single ) 
declare sub DrawMap()


''*****************************************************************************
const as integer SCREEN_WIDTH = 640
const as integer SCREEN_HEIGHT = 480

const as integer TILE_SIZE = 32


const as integer MAP_WID = SCREEN_WIDTH\TILE_SIZE      '' 20
const as integer MAP_HEI = SCREEN_HEIGHT\TILE_SIZE      '' 15

const as integer FALSE = 0
const as integer TRUE = not FALSE

const as single Gravity = 0.75
const as single JumpHeight = 15


''*****************************************************************************
dim shared as integer Map(MAP_WID-1,MAP_HEI-1) =>_
{{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},_  ''1
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''2
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''3
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''4
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''5
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},_   ''6
{1,0,0,0,0,0,0,0,0,0,1,0,0,0,1},_   ''7
{1,0,0,0,0,0,0,1,0,0,1,0,0,0,1},_   ''8
{1,0,0,0,0,1,0,0,0,0,0,0,0,0,1},_   ''9
{1,0,0,0,0,0,0,0,0,0,0,0,1,0,1},_   ''10
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''11
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''12
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},_   ''13
{1,0,0,0,0,0,1,0,0,0,0,0,1,0,1},_   ''14
{1,0,0,0,0,0,0,0,0,0,0,1,0,0,1},_   ''15
{1,0,0,0,0,0,1,0,0,0,0,1,0,0,1},_   ''16
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''17
{1,0,0,0,0,1,0,0,0,0,0,0,0,0,1},_   ''18
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},_   ''19
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}}


''*****************************************************************************
''
''
''
''*****************************************************************************
type Player

	x		as single
	y		as single
	speed	as single
	xv		as single
	yv		as single
	wid		as integer
	hei		as integer
	
	CanJump as integer
	
	declare constructor()
	declare function CollideFloors(byval ix as integer, byval iy as integer, byref TileY as integer, Map() as integer ) as integer
	declare function CollideWalls(byval ix as integer, byval iy as integer, byref TileX as integer, Map() as integer ) as integer
	declare sub DoStuff()
	declare sub CollideOnMap( Map() as integer )
	declare sub Draw3D()
	
end type

constructor Player()
	x = 32 * 2 
	y = 32 * 5 
	speed = 4.5
	wid = 24
	hei = 48
	CanJump = false
End Constructor



function Player.CollideWalls(byval ix as integer, byval iy as integer, byref TileX as integer, Map() as integer ) as integer
	
	dim as integer TileYpixels = iy - (iy mod TILE_SIZE)   '' Pixel of the player's head snapped to map grid
	dim as integer TestEnd = iy + hei					   '' Foot of the player
	
	TileX = ix\TILE_SIZE								   '' Current X map coord the player is on + x-velocity(+ width when moving right)
	
	dim as integer TileY = TileYpixels\TILE_SIZE		   '' Current Y map coord of the player's head
	
	'' Scan downwards from head to foot if we collided with a tile on the right or left
	while (TileYpixels <= TestEnd)
		if (Map(TileX, TileY))	then return true		   '' Found a tile

		TileY += 1										   '' Next tile downward
		TileYpixels +=TILE_SIZE							   '' Next tile pixel downward
		
	Wend
	
	return false
End Function

function Player.CollideFloors(byval ix as integer, byval iy as integer, byref TileY as integer, Map() as integer ) as integer
	
	dim as integer TileXpixels = ix - (ix mod TILE_SIZE)
	dim as integer TestEnd = ix + wid
	
	TileY = iy\TILE_SIZE
	
	dim as integer TileX = TileXpixels\TILE_SIZE
	
	while (TileXpixels <= TestEnd)
		if (Map(TileX, TileY))	then return true	

		TileX += 1
		TileXpixels +=TILE_SIZE
		
	Wend
	
	return false
End Function



sub Player.DoStuff()

	xv = 0
	
	if multikey(FB.SC_LEFT) then 
		xv = -speed
	EndIf
	
    if multikey(FB.SC_RIGHT) then 
    	xv = speed
    EndIf
    
    if multikey(FB.SC_SPACE) then 
	    if( CanJump ) then
	    	yv = -JumpHeight
	    	CanJump = false
	    end if
    EndIf
    
    
    
End Sub

sub Player.CollideOnMap( Map() as integer )
	
	dim as Integer TileX, TileY

	if( xv > 0 ) then
		
		if( CollideWalls( x + xv + wid, y, TileX, Map() ) ) then
			x = TileX * TILE_SIZE - wid - 1
		else
			x += xv
		EndIf
			
	elseif( xv < 0 ) then
		
		if( CollideWalls( x + xv, y, TileX, Map() ) ) then
			x = ( TileX + 1 ) * TILE_SIZE + 1
		else
			x += xv
		EndIf
		
	EndIf
	
	if( yv < 0 ) then
		
		if( CollideFloors( x, y + yv, TileY, Map() ) ) then   '' hit the roof
			y = ( TileY + 1 ) * TILE_SIZE + 1
			yv = 0    
		else
			y += yv
			yv += Gravity
		EndIf
			
	else
		
		if( CollideFloors( x, y + yv + hei, TileY, Map() ) ) then
			y = ( TileY ) * TILE_SIZE - hei - 1
			yv = 1
			if not multikey(FB.SC_SPACE) then CanJump = true
		else
			y += yv
			yv += Gravity
			CanJump = false
		EndIf
		
	EndIf
	
	
End Sub


sub Player.Draw3D()

	'' Draws the player in 3D	
	dim as single SizeX = Wid/2.0
	dim as single SizeY = Hei/2.0
	
	
	glColor4f( 1, 0, 1, 1 )
	glPushMatrix()
		glTranslatef( x + Wid/2, y + Hei/2.0, 0) '' Offset by Size/2 so that we draw from top-left at (0,0)
		glBegin(GL_QUADS)
			glVertex3f(-SizeX, -SizeY,  0)
			glVertex3f( SizeX, -SizeY,  0)
			glVertex3f( SizeX,  SizeY,  0)
			glVertex3f(-SizeX,  SizeY,  0)			
		glEnd()
	glPopMatrix()
	
	
end sub

	
''*****************************************************************************
''
''
''
''*****************************************************************************

Type Vector2D

	x as Single
	y as Single
	z as single
	
end type

Type Camera
	
	
	declare Constructor()
	declare sub Follow( x as single, y as single )
	declare sub Look()
	declare sub Look( value as single )
	declare sub Zoom( value as single )

	
	
	Position as Vector2D 
	Target as Vector2D 
	Up as Vector2D 
	
	EyeDistanceFromScreen as integer

end type


constructor Camera()

	EyeDistanceFromScreen = TILE_SIZE * 18   '' Distance of player's eye from screen
	
	Position.x = 0
	Position.y = 0
	Position.z = EyeDistanceFromScreen       '' Yep we are drawing at z = 0 so pos should be positive
	
	Target.x = 0
	Target.y = 0
	Target.z = 0
	
	Up.x = 0
	Up.y = 1
	Up.z = 0
	
	
end constructor	

sub Camera.Follow( x as single, y as single )

	
	Position.x = x
	Position.y = y - TILE_SIZE * 1    		'' offset a little above so we look a little down
	Position.z = EyeDistanceFromScreen      '' move zpos n units from screen to eye
	
	Target.x = x
	Target.y = y
	Target.z = 0
	
	Up.x = 0
	Up.y = 1
	Up.z = 0
	
end sub


sub Camera.Look()

	
	gluLookAt( Position.x, Position.y, Position.z,_    '' camera pos
			   Target.x, Target.y, Target.z,_     	  '' camera target
               Up.x, Up.y, Up.z)

end sub



sub Camera.Zoom( value as single )

	EyeDistanceFromScreen +=value

end sub
	

''*****************************************************************************
sub main()
	
	
	dim as integer Frame = 0
	 
	dim as Camera Cam
	dim as Player Mario
	 
	GL_Screen_Init( SCREEN_WIDTH, SCREEN_HEIGHT )   ''Set up GL screen

	
	do
		
		Frame += 1

		Mario.DoStuff()     '' Do player movements
    
		Mario.CollideOnMap( Map() )		'' Do collisions in 2D
		
		
		'' Zoom if you want
		if( multikey(FB.SC_F2) ) then Cam.Zoom(1.62)
		if( multikey(FB.SC_F3) ) then Cam.Zoom(-1.62)
		
		
		
		glMatrixMode( GL_MODELVIEW )
		glLoadIdentity() 
		glPolygonMode( GL_FRONT, GL_FILL )
		glPolygonMode( GL_BACK, GL_FILL )
		glEnable( GL_DEPTH_TEST )
		glDepthFunc( GL_LEQUAL )
		
		glDisable( GL_TEXTURE_2D )
	
		
		glColor4ub( 255, 255, 255, 255 )

		'' Just fix the camera to the center of the screen
		Cam.Follow( SCREEN_WIDTH\2, SCREEN_HEIGHT\2 )
		
		'' reverse y direction for oldskool coords(Easy GL2D = happy)
		glScalef( 1, -1, 1 )
		
		'' Look
		Cam.Look()
		
		'' Paper mario?
		if( multikey(FB.SC_F1) ) then glRotatef( 20, 0, 1, 0 )
		
		'' Clear screen
		glClear(GL_COLOR_BUFFER_BIT OR GL_DEPTH_BUFFER_BIT)

		'' Draw 3D stuff
		glPushMatrix()   
					
			DrawMap()
			Mario.Draw3D()

		glPopMatrix()    
		
		'' limit FPS
		dim as single TimeStart = timer
		while( (timer - TimeStart) < (1.0/60.0) )
			sleep 1,1
		wend
		
		
		flip
		
	Loop until multikey(FB.SC_ESCAPE)

	
	
End Sub



main()


end








''*****************************************************************************
'' Temp way to draw our 32x32 tiles
sub DrawCube( x as single, y as single, z as single, Size as single, Red as single, Green as single, Blue as single )

	glColor4f( Red, Green, Blue, 1 )
	
	glPushMatrix()
		glTranslatef( x + Size, y + Size, z)  '' Offset by Size so that we draw from top-left at (0,0)
	
		glBegin(GL_QUADS)
			'' Front Face
			glColor3f( 1, 0, 0)
			glVertex3f(-Size, -Size,  Size)
			glColor3f( 0, 1, 0)
			glVertex3f( Size, -Size,  Size)
			glColor3f( 0, 0, 1)
			glVertex3f( Size,  Size,  Size)
			glColor3f( 1, 1, 1)
			glVertex3f(-Size,  Size,  Size)
			
			glColor4f( 1, 1, 0, 1 )
	
			'' Back Face
			glVertex3f(-Size, -Size, -Size)
			glVertex3f(-Size,  Size, -Size)
			glVertex3f( Size,  Size, -Size)
			glVertex3f( Size, -Size, -Size)
			'' Top Face
			glVertex3f(-Size,  Size, -Size)
			glVertex3f(-Size,  Size,  Size)
			glVertex3f( Size,  Size,  Size)
			glVertex3f( Size,  Size, -Size)
			'' Bottom Face
			glVertex3f(-Size, -Size, -Size)
			glVertex3f( Size, -Size, -Size)
			glVertex3f( Size, -Size,  Size)
			glVertex3f(-Size, -Size,  Size)
			'' Right face
			glVertex3f( Size, -Size, -Size)
			glVertex3f( Size,  Size, -Size)
			glVertex3f( Size,  Size,  Size)
			glVertex3f( Size, -Size,  Size)
			'' Left Face
			glVertex3f(-Size, -Size, -Size)
			glVertex3f(-Size, -Size,  Size)
			glVertex3f(-Size,  Size,  Size)
			glVertex3f(-Size,  Size, -Size)
		glEnd()
	
	glPopMatrix()
	
	glColor4f( 1, 1, 1, 1 )
	
	
end sub


'' Draws the map in 3D
sub DrawMap()

	for y as integer = 0 to (MAP_HEI - 1)
		for x as integer = 0 to (MAP_WID - 1)
			if( Map(x,y) > 0 ) then			
				DrawCube( x * TILE_SIZE, y * TILE_SIZE, 0, TILE_SIZE/2, 0, 1, 0 )
			end if
		next x	
	next y
	
end sub


''=============================================================================
''
''    Sets up OpenGL for 2d mode
''
''=============================================================================
sub GL_Screen_Init(byval screen_wid as integer, byval screen_hei as integer, byval flags as integer = 0)
	
	if flags then
		screenres screen_wid, screen_hei, 32, 2, FB.GFX_OPENGL or flags
	else
		screenres screen_wid, screen_hei, 32, 2, FB.GFX_OPENGL
	endif
	
	
	'screen information 
	dim w as integer, h as integer 
	'OpenGL params for gluerspective 
	dim FOVy as double            'Field of view angle in Y 
	dim Aspect as double          'Aspect of screen 
	dim znear as double           'z-near clip distance 
	dim zfar as double            'z-far clip distance 

	'using screen info w and h as params 
	glViewport(0, 0, screen_wid, screen_hei)
	
	'Set current Mode to projection(ie: 3d) 
	glMatrixMode(GL_PROJECTION) 
	
	'Load identity matrix to projection matrix 
	glLoadIdentity() 

	'Set gluPerspective params 
	FOVy = 90/2                                     '45 deg fovy 
	Aspect = screen_wid / screen_hei
	znear = 1                                       'Near clip 
	zfar = 1500                                     'far clip 
	
	'use glu Perspective to set our 3d frustum dimension up 
	gluPerspective(FOVy, aspect, znear, zfar) 
	
	'Modelview mode 
	'ie. Matrix that does things to anything we draw 
	'as in lines, points, tris, etc. 
	glMatrixMode(GL_MODELVIEW) 
	'load identity(clean) matrix to modelview 
	glLoadIdentity() 
	
	glShadeModel(GL_SMOOTH)                 'set shading to smooth(try GL_FLAT) 
	glClearColor(0.0, 0.0, 0.0, 1.0)        'set Clear color to BLACK 
	glClearDepth(1.0)                       'Set Depth buffer to 1(z-Buffer) 
	glEnable(GL_DEPTH_TEST)                 'Enable Depth Testing so that our z-buffer works 
	
	'compare each incoming pixel z value with the z value present in the depth buffer 
	'LEQUAL means than pixel is drawn if the incoming z value is less than 
	'or equal to the stored z value 
	glDepthFunc(GL_LEQUAL) 
	
	'have one or more material parameters track the current color 
	'Material is your 3d model 
	glEnable(GL_COLOR_MATERIAL) 


    'Enable Texturing 
    glEnable(GL_TEXTURE_2D) 
    

   	'Tell openGL that we want the best possible perspective transform 
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST) 
	
	'Disable Backface culling
	glDisable (GL_CULL_FACE)
	
	glPolygonMode(GL_FRONT, GL_FILL) 
	
	'' enable blending for transparency 
	glEnable(GL_BLEND)    	    
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
	
	glDisable( GL_DEPTH_TEST )
	
	glEnable( GL_ALPHA_TEST )
	glAlphaFunc(GL_GREATER, 0)


	glDisable(GL_STENCIL_TEST)
	glDisable(GL_TEXTURE_1D)
	glDisable(GL_LIGHTING)
	glDisable(GL_LOGIC_OP)
	glDisable(GL_DITHER)
	glDisable(GL_FOG)

	glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST)
	glHint(GL_LINE_SMOOTH_HINT , GL_FASTEST)

	glPointSize( 1 )
	glLineWidth( 1 )
	
	
end sub



6. Debug( Just to show you the relationship between 2D and 3D )

Code: Select all

''*****************************************************************************
'' 
''   2.5D Engine (Added a 2d mode so that 1:1 ratio can be verified)
''   Relminator (Richard Eric M. Lope)
''	 http://rel.phatcode.net
''
''	 This is probably the easiest way to make a 3d game
''   Features:
''   * 1:1 ratio of 3D coords to Screen
''   * Collisions are in tilebased 2D
''   * Rendering can be camera based (uber fast)
''   * Any 2D tilebased game can be converted to this
''
''   Controls
''   
''   SPACE = Jump
''   ARROW KEYS = Move
''   F1 = Paper mario mode?
''   F2/F3 = Zoom
''
''*****************************************************************************

#include once "fbgfx.bi"
#include once "/gl/gl.bi" 
#include once "/gl/glu.bi"   


''*****************************************************************************
'' Easy GL2D stuff (needed for printing and debugging)
#define ARGB_A(u) (((u) shr 24) and &H000000FF)
#define ARGB_R(u) (((u) shr 16) and &H000000FF)
#define ARGB_G(u) (((u) shr 8)  and &H000000FF)
#define ARGB_B(u) (((u) shr 0)  and &H000000FF)
#define ARGB( r, g, b, a )   rgba( (b), (g), (r), (a) )
#define GL2D_RGBA( r, g, b, a )   rgba( (b), (g), (r), (a) )

dim shared as GLuint current_texture = 0
dim shared as GLuint font_list_base = 0
dim shared as GLuint font_textureID = 0

declare sub GL2D_Screen_Init(byval screen_wid as integer, byval screen_hei as integer, byval flags as integer = 0)
declare sub GL2D_Clear_Screen()
declare sub GL2D_Begin2D(byval wid as integer, byval hei as integer)
declare sub GL2D_End2D()  
declare sub GL2D_Print_Scale(byval x as integer, byval y as integer, byval scale as single, byref text as const string)
declare sub GL2D_Box( byval x1 as integer, byval y1 as integer, byval x2 as integer, byval y2 as integer, byval gl2dcolor as GLuint )
declare sub GL2D_Box_Filled( byval x1 as integer, byval y1 as integer, byval x2 as integer, byval y2 as integer, byval gl2dcolor as GLuint )
declare sub GL2D_VsyncOn()

'' Drawing stuff
''*****************************************************************************
declare sub DrawCube( x as single, y as single, z as single, Size as single, Red as single, Green as single, Blue as single ) 
declare sub DrawMap()
declare sub DrawMap2D()


''*****************************************************************************
const as integer SCREEN_WIDTH = 640
const as integer SCREEN_HEIGHT = 480

const as integer TILE_SIZE = 32


const as integer MAP_WID = SCREEN_WIDTH\TILE_SIZE      '' 20
const as integer MAP_HEI = SCREEN_HEIGHT\TILE_SIZE      '' 15

const as integer FALSE = 0
const as integer TRUE = not FALSE

const as single Gravity = 0.75
const as single JumpHeight = 15


''*****************************************************************************
dim shared as integer Map(MAP_WID-1,MAP_HEI-1) =>_
{{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},_  ''1
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''2
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''3
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''4
{1,0,0,1,0,0,0,0,0,0,1,0,0,0,1},_   ''5
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},_   ''6
{1,0,0,0,0,0,0,0,0,0,1,0,0,0,1},_   ''7
{1,0,0,0,0,0,0,1,0,0,1,0,0,0,1},_   ''8
{1,0,0,0,0,1,0,0,0,0,0,0,0,0,1},_   ''9
{1,0,0,0,0,0,0,0,0,0,0,0,1,0,1},_   ''10
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''11
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''12
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},_   ''13
{1,0,0,0,0,0,1,0,0,0,0,0,1,0,1},_   ''14
{1,0,0,0,0,0,0,0,0,0,0,1,0,0,1},_   ''15
{1,0,0,0,0,0,1,0,0,0,0,1,0,0,1},_   ''16
{1,0,0,0,0,1,0,0,0,0,0,0,1,0,1},_   ''17
{1,0,0,0,0,1,0,0,0,0,0,0,0,0,1},_   ''18
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},_   ''19
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}}


''*****************************************************************************
''
''
''
''*****************************************************************************
type Player

	x		as single
	y		as single
	speed	as single
	xv		as single
	yv		as single
	wid		as integer
	hei		as integer
	
	CanJump as integer
	
	declare constructor()
	declare function CollideFloors(byval ix as integer, byval iy as integer, byref TileY as integer, Map() as integer ) as integer
	declare function CollideWalls(byval ix as integer, byval iy as integer, byref TileX as integer, Map() as integer ) as integer
	declare sub DoStuff()
	declare sub CollideOnMap( Map() as integer )
	declare sub Draw3D()
	declare sub Draw2D()
	
end type

constructor Player()
	x = 32 * 2 
	y = 32 * 5 
	speed = 4.5
	wid = 24
	hei = 48
	CanJump = false
End Constructor



function Player.CollideWalls(byval ix as integer, byval iy as integer, byref TileX as integer, Map() as integer ) as integer
	
	dim as integer TileYpixels = iy - (iy mod TILE_SIZE)   '' Pixel of the player's head snapped to map grid
	dim as integer TestEnd = iy + hei					   '' Foot of the player
	
	TileX = ix\TILE_SIZE								   '' Current X map coord the player is on + x-velocity(+ width when moving right)
	
	dim as integer TileY = TileYpixels\TILE_SIZE		   '' Current Y map coord of the player's head
	
	'' Scan downwards from head to foot if we collided with a tile on the right or left
	while (TileYpixels <= TestEnd)
		if (Map(TileX, TileY))	then return true		   '' Found a tile

		TileY += 1										   '' Next tile downward
		TileYpixels +=TILE_SIZE							   '' Next tile pixel downward
		
	Wend
	
	return false
End Function

function Player.CollideFloors(byval ix as integer, byval iy as integer, byref TileY as integer, Map() as integer ) as integer
	
	dim as integer TileXpixels = ix - (ix mod TILE_SIZE)
	dim as integer TestEnd = ix + wid
	
	TileY = iy\TILE_SIZE
	
	dim as integer TileX = TileXpixels\TILE_SIZE
	
	while (TileXpixels <= TestEnd)
		if (Map(TileX, TileY))	then return true	

		TileX += 1
		TileXpixels +=TILE_SIZE
		
	Wend
	
	return false
End Function



sub Player.DoStuff()

	xv = 0
	
	if multikey(FB.SC_LEFT) then 
		xv = -speed
	EndIf
	
    if multikey(FB.SC_RIGHT) then 
    	xv = speed
    EndIf
    
    if multikey(FB.SC_SPACE) then 
	    if( CanJump ) then
	    	yv = -JumpHeight
	    	CanJump = false
	    end if
    EndIf
    
    
    
End Sub

sub Player.CollideOnMap( Map() as integer )
	
	dim as Integer TileX, TileY

	if( xv > 0 ) then
		
		if( CollideWalls( x + xv + wid, y, TileX, Map() ) ) then
			x = TileX * TILE_SIZE - wid - 1
		else
			x += xv
		EndIf
			
	elseif( xv < 0 ) then
		
		if( CollideWalls( x + xv, y, TileX, Map() ) ) then
			x = ( TileX + 1 ) * TILE_SIZE + 1
		else
			x += xv
		EndIf
		
	EndIf
	
	if( yv < 0 ) then
		
		if( CollideFloors( x, y + yv, TileY, Map() ) ) then   '' hit the roof
			y = ( TileY + 1 ) * TILE_SIZE + 1
			yv = 0    
		else
			y += yv
			yv += Gravity
		EndIf
			
	else
		
		if( CollideFloors( x, y + yv + hei, TileY, Map() ) ) then
			y = ( TileY ) * TILE_SIZE - hei - 1
			yv = 1
			if not multikey(FB.SC_SPACE) then CanJump = true
		else
			y += yv
			yv += Gravity
			CanJump = false
		EndIf
		
	EndIf
	
	
End Sub


sub Player.Draw3D()

	'' Draws the player in 3D	
	dim as single SizeX = Wid/2.0
	dim as single SizeY = Hei/2.0
	
	
	glColor4f( 1, 0, 1, 1 )
	glPushMatrix()
		glTranslatef( x + Wid/2, y + Hei/2.0, 0) '' Offset by Size/2 so that we draw from top-left at (0,0)
		glBegin(GL_QUADS)
			glVertex3f(-SizeX, -SizeY,  0)
			glVertex3f( SizeX, -SizeY,  0)
			glVertex3f( SizeX,  SizeY,  0)
			glVertex3f(-SizeX,  SizeY,  0)			
		glEnd()
	glPopMatrix()
	
	
end sub

sub Player.Draw2D()
	
	'' 2D mode for debugging
	GL2D_Box( x, y, x + Wid, y + Hei, GL2D_RGBA(255,0,255, 255) )
	
end sub
	
''*****************************************************************************
''
''
''
''*****************************************************************************

Type Vector2D

	x as Single
	y as Single
	z as single
	
end type

Type Camera
	
	
	declare Constructor()
	declare sub Follow( x as single, y as single )
	declare sub Look()
	declare sub Zoom( value as single )

	
	
	Position as Vector2D 
	Target as Vector2D 
	Up as Vector2D 
	
	EyeDistanceFromScreen as integer

end type


constructor Camera()

	EyeDistanceFromScreen = TILE_SIZE * 18   '' Distance of player's eye from screen
	
	Position.x = 0
	Position.y = 0
	Position.z = EyeDistanceFromScreen       '' Yep we are drawing at z = 0 so pos should be positive
	
	Target.x = 0
	Target.y = 0
	Target.z = 0
	
	Up.x = 0
	Up.y = 1
	Up.z = 0
	
	
end constructor	

sub Camera.Follow( x as single, y as single )

	
	Position.x = x
	Position.y = y - TILE_SIZE * 1    		'' offset a little above so we look a little down
	Position.z = EyeDistanceFromScreen      '' move zpos n units from screen to eye
	
	Target.x = x
	Target.y = y
	Target.z = 0
	
	Up.x = 0
	Up.y = 1
	Up.z = 0
	
end sub


sub Camera.Look()

	
	gluLookAt( Position.x, Position.y, Position.z,_    '' camera pos
			   Target.x, Target.y, Target.z,_     	  '' camera target
               Up.x, Up.y, Up.z)

end sub

sub Camera.Zoom( value as single )

	EyeDistanceFromScreen +=value

end sub
	

''*****************************************************************************
sub main()
	
	
	dim as integer Frame = 0
	 
	dim as Camera Cam
	dim as Player Mario
	 
	GL2D_Screen_Init( SCREEN_WIDTH, SCREEN_HEIGHT )   ''Set up GL screen

	
	do
		
		Frame += 1

		Mario.DoStuff()     '' Do player movements
    
		Mario.CollideOnMap( Map() )		'' Do collisions in 2D
		
		
		'' Zoom if you want
		if( multikey(FB.SC_F2) ) then Cam.Zoom(1.62)
		if( multikey(FB.SC_F3) ) then Cam.Zoom(-1.62)
		
		
		
		glMatrixMode( GL_MODELVIEW )
		glLoadIdentity() 
		glPolygonMode( GL_FRONT, GL_FILL )
		glPolygonMode( GL_BACK, GL_FILL )
		glEnable( GL_DEPTH_TEST )
		glDepthFunc( GL_LEQUAL )
		
		glDisable( GL_TEXTURE_2D )
	
		
		glColor4ub( 255, 255, 255, 255 )

		'' Move cam according to player's pos
		Cam.Follow( Mario.x, Mario.y )
		
		'' reverse y direction for oldskool coords(Easy GL2D = happy)
		glScalef( 1, -1, 1 )
		
		'' Look
		Cam.Look()
		
		'' Paper mario?
		if( multikey(FB.SC_F1) ) then glRotatef( 20, 0, 1, 0 )
		
		'' Clear screen
		GL2D_Clear_Screen()

		'' Draw 3D stuff
		glPushMatrix()   
					
			DrawMap()
			Mario.Draw3D()

		glPopMatrix()    
		
		'' 2D mode
		GL2D_Begin2D( SCREEN_WIDTH, SCREEN_HEIGHT )
		
			glEnable( GL_TEXTURE_2D )
			
			DrawMap2D()
			Mario.Draw2D()
			
			glColor4ub(255,255,255,255)  '' no transluceny
			GL2D_Print_Scale(0,  0, 1, "TileX = " & Mario.x\TILE_SIZE )
			GL2D_Print_Scale(0, 10, 1, "TileY = " & Mario.y\TILE_SIZE )
			
			GL2D_Print_Scale(0, 30, 1, "Controls:")
			GL2D_Print_Scale(0, 40, 1, "SPACE = Jump" )
			GL2D_Print_Scale(0, 50, 1, "F1 = Skew cam" )
			GL2D_Print_Scale(0, 60, 1, "F2/F3 = zoom/pan cam" )
			
			
			
		GL2D_End2D()
		
		'' limit FPS
		dim as single TimeStart = timer
		while( (timer - TimeStart) < (1.0/60.0) )
			sleep 1,1
		wend
		
		
		flip
		
	Loop until multikey(FB.SC_ESCAPE)

	
	
End Sub



main()


end








''*****************************************************************************
'' Temp way to draw our 32x32 tiles
sub DrawCube( x as single, y as single, z as single, Size as single, Red as single, Green as single, Blue as single )

	glColor4f( Red, Green, Blue, 1 )
	
	glPushMatrix()
		glTranslatef( x + Size, y + Size, z)  '' Offset by Size so that we draw from top-left at (0,0)
	
		glBegin(GL_QUADS)
			'' Front Face
			glColor3f( 1, 0, 0)
			glVertex3f(-Size, -Size,  Size)
			glColor3f( 0, 1, 0)
			glVertex3f( Size, -Size,  Size)
			glColor3f( 0, 0, 1)
			glVertex3f( Size,  Size,  Size)
			glColor3f( 1, 1, 1)
			glVertex3f(-Size,  Size,  Size)
			
			glColor4f( 1, 1, 0, 1 )
	
			'' Back Face
			glVertex3f(-Size, -Size, -Size)
			glVertex3f(-Size,  Size, -Size)
			glVertex3f( Size,  Size, -Size)
			glVertex3f( Size, -Size, -Size)
			'' Top Face
			glVertex3f(-Size,  Size, -Size)
			glVertex3f(-Size,  Size,  Size)
			glVertex3f( Size,  Size,  Size)
			glVertex3f( Size,  Size, -Size)
			'' Bottom Face
			glVertex3f(-Size, -Size, -Size)
			glVertex3f( Size, -Size, -Size)
			glVertex3f( Size, -Size,  Size)
			glVertex3f(-Size, -Size,  Size)
			'' Right face
			glVertex3f( Size, -Size, -Size)
			glVertex3f( Size,  Size, -Size)
			glVertex3f( Size,  Size,  Size)
			glVertex3f( Size, -Size,  Size)
			'' Left Face
			glVertex3f(-Size, -Size, -Size)
			glVertex3f(-Size, -Size,  Size)
			glVertex3f(-Size,  Size,  Size)
			glVertex3f(-Size,  Size, -Size)
		glEnd()
	
	glPopMatrix()
	
	glColor4f( 1, 1, 1, 1 )
	
	
end sub


'' Draws the map in 3D
sub DrawMap()

	for y as integer = 0 to (MAP_HEI - 1)
		for x as integer = 0 to (MAP_WID - 1)
			if( Map(x,y) > 0 ) then			
				DrawCube( x * TILE_SIZE, y * TILE_SIZE, 0, TILE_SIZE/2, 0, 1, 0 )
			end if
		next x	
	next y
	
end sub

'' Draws the map in 2D
sub DrawMap2D()

	for y as integer = 0 to (MAP_HEI - 1)
		for x as integer = 0 to (MAP_WID - 1)
			if( Map(x,y) > 0 ) then			
				GL2D_Box( x * TILE_SIZE, y * TILE_SIZE, x * TILE_SIZE + TILE_SIZE, y * TILE_SIZE + TILE_SIZE, GL2D_RGBA(255,0,0, 255) )
			end if
		next x	
	next y
	
end sub



''*****************************************************************************
'' Easy GL2D stuff (needed for printing and debugging)
sub GL2D_VsyncOn()
	
	dim swapinterval as function(byval interval as integer) as integer
	dim extensions as string
	
	'' setup opengl and retrieve supported extensions
	screencontrol FB.GET_GL_EXTENSIONS, extensions
	
	if (instr(extensions, "WGL_EXT_swap_control") <> 0) then
	    '' extension supported, retrieve proc address
	    swapinterval = ScreenGLProc("wglSwapIntervalEXT")
	else
		swapinterval = ScreenGLProc("glXSwapIntervalSGI")
	end if

    if (swapinterval <> 0) then
        '' ok, we got it. set opengl to wait for vertical sync on buffer swaps
        swapinterval(1)
    end if

end sub


sub GL2D_Begin2D(byval wid as integer, byval hei as integer)
	
    glMatrixMode(GL_PROJECTION)    
    glPushMatrix()
    glLoadIdentity()
    glOrtho(0, wid, hei, 0, -1, 1)
    glMatrixMode(GL_MODELVIEW)
    glPushMatrix()
    glLoadIdentity()
    glTranslatef(0.375, 0.375, 0)	'' magic trick
    
end sub

sub GL2D_End2D()  
	
    glMatrixMode(GL_PROJECTION)
    glPopMatrix()
    glMatrixMode(GL_MODELVIEW)
    glPopMatrix()
    
end sub


function GL2D_Load_Image_24bit_Alpha( byval spr as any ptr, byval filter_mode as GLuint = GL_NEAREST ) as GLuint
	
        dim as GLuint TextureID
   		dim as ubyte r, g, b, a
   		dim As FB.IMAGE ptr temp = spr
   		
   		for y as integer = 0 to temp->height-1
	    	dim as uinteger ptr p = cast(uinteger ptr,(spr + sizeof (FB.IMAGE)) + y * temp->pitch)	   
		    for x as integer = 0 to temp->width-1
		    	a = argb_a(p[x])
		    	r = argb_r(p[x])
		    	g = argb_g(p[x])
		    	b = argb_b(p[x])
		    	'' check for transparency
				if ( g = 0 ) then
					if ( (r = 255) and (b = 255) ) then
						p[x] = rgba(r,g,b,0)
					endif
				endif
		    next x
   		next y
   		
   		
   		glEnable( GL_TEXTURE_2D )
        glGenTextures(1, @TextureID)
        glBindTexture(GL_TEXTURE_2D, TextureID)
        
   		glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT )
        glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT )
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter_mode )
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter_mode )
        glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE )
               
        glTexImage2d( GL_TEXTURE_2D, 0, GL_RGBA, temp->width, temp->height,_
        			  0, GL_BGRA, GL_UNSIGNED_BYTE, spr + sizeof(FB.IMAGE) )
        glBindTexture(GL_TEXTURE_2D, 0)
        
        
        return TextureID
        
end function


sub GL2D_Font_Init()

	
    dim as any ptr image = imagecreate(128,128,RGBA(255,0,255,0))
    
    for x as integer = 0 to 15
        for y as integer = 0 to 15
        	draw string image, (x * 8, y * 8), chr( x + y * 16)
        next
    next

	
	font_textureID = GL2D_Load_Image_24bit_Alpha( image )
	

    imagedestroy( image )


    font_list_base = glGenLists(256)
    dim as single scale = 1/128
    dim as single w = 8 * scale
    dim as single h = 8 * scale

    glPushMatrix()
    glLoadIdentity()
    for font_loop as integer = 0 to 255
	    
	    dim as single x = (font_loop mod 16) * w
	    dim as single y = fix(font_loop / 16) * h
	    
	    glNewList( font_list_base + font_loop, GL_COMPILE )
	    glBegin( GL_QUADS )
	            glTexCoord2f( x, y + h)
	            glVertex2i( 0, 8 )
	           
	            glTexCoord2f( x + w, y + h )
	            glVertex2i( 8, 8 )
	           
	            glTexCoord2f( x + w,y )
	            glVertex2i( 8, 0 )
	           
	            glTexCoord2f( x, y )
	            glVertex2i( 0, 0 )
	    glEnd()
	    
	    glTranslatef( 8,0,0 )
	    glEndList()
	    
    next font_loop

	glPopMatrix()
	
end sub

''=============================================================================
''
''    Sets up OpenGL for 2d mode
''
''=============================================================================
sub GL2D_Screen_Init(byval screen_wid as integer, byval screen_hei as integer, byval flags as integer = 0)
	
	if flags then
		screenres screen_wid, screen_hei, 32, 2, FB.GFX_OPENGL or flags
	else
		screenres screen_wid, screen_hei, 32, 2, FB.GFX_OPENGL
	endif
	
	
	'screen information 
	dim w as integer, h as integer 
	'OpenGL params for gluerspective 
	dim FOVy as double            'Field of view angle in Y 
	dim Aspect as double          'Aspect of screen 
	dim znear as double           'z-near clip distance 
	dim zfar as double            'z-far clip distance 

	'using screen info w and h as params 
	glViewport(0, 0, screen_wid, screen_hei)
	
	'Set current Mode to projection(ie: 3d) 
	glMatrixMode(GL_PROJECTION) 
	
	'Load identity matrix to projection matrix 
	glLoadIdentity() 

	'Set gluPerspective params 
	FOVy = 90/2                                     '45 deg fovy 
	Aspect = screen_wid / screen_hei
	znear = 1                                       'Near clip 
	zfar = 1500                                     'far clip 
	
	'use glu Perspective to set our 3d frustum dimension up 
	gluPerspective(FOVy, aspect, znear, zfar) 
	
	'Modelview mode 
	'ie. Matrix that does things to anything we draw 
	'as in lines, points, tris, etc. 
	glMatrixMode(GL_MODELVIEW) 
	'load identity(clean) matrix to modelview 
	glLoadIdentity() 
	
	glShadeModel(GL_SMOOTH)                 'set shading to smooth(try GL_FLAT) 
	glClearColor(0.0, 0.0, 0.0, 1.0)        'set Clear color to BLACK 
	glClearDepth(1.0)                       'Set Depth buffer to 1(z-Buffer) 
	glDisable(GL_DEPTH_TEST)                'Disable Depth Testing so that our z-buffer works 
	
	'compare each incoming pixel z value with the z value present in the depth buffer 
	'LEQUAL means than pixel is drawn if the incoming z value is less than 
	'or equal to the stored z value 
	glDepthFunc(GL_LEQUAL) 
	
	'have one or more material parameters track the current color 
	'Material is your 3d model 
	glEnable(GL_COLOR_MATERIAL) 


    'Enable Texturing 
    glEnable(GL_TEXTURE_2D) 
    

   	'Tell openGL that we want the best possible perspective transform 
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST) 
	
	'Disable Backface culling
	glDisable (GL_CULL_FACE)
	
	glPolygonMode(GL_FRONT, GL_FILL) 
	
	'' enable blending for transparency 
	glEnable(GL_BLEND)    	    
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
	
	glDisable( GL_DEPTH_TEST )
	
	glEnable( GL_ALPHA_TEST )
	glAlphaFunc(GL_GREATER, 0)


	glDisable(GL_STENCIL_TEST)
	glDisable(GL_TEXTURE_1D)
	glDisable(GL_LIGHTING)
	glDisable(GL_LOGIC_OP)
	glDisable(GL_DITHER)
	glDisable(GL_FOG)

	glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST)
	glHint(GL_LINE_SMOOTH_HINT , GL_FASTEST)

	glPointSize( 1 )
	glLineWidth( 1 )
	
	'' set up the font system
	GL2D_Font_Init()

end sub

sub GL2D_Clear_Screen()
	
	glClear(GL_COLOR_BUFFER_BIT OR GL_DEPTH_BUFFER_BIT)

end sub

sub GL2D_Box( byval x1 as integer, byval y1 as integer, byval x2 as integer, byval y2 as integer, byval gl2dcolor as GLuint )

	glDisable( GL_TEXTURE_2D )
	glColor4ubv( cast( GLubyte ptr, @gl2dcolor ) )
	
    
	glBegin( GL_LINE_STRIP )
		glVertex2i( x1, y1 )
		glVertex2i( x2, y1 )
		glVertex2i( x2, y2 )
		glVertex2i( x1, y2 )
		glVertex2i( x1, y1 )
	glEnd()
	
	
	glEnable( GL_TEXTURE_2D )
	
	glColor4ub(255,255,255,255)
	
end sub


sub GL2D_Box_Filled( byval x1 as integer, byval y1 as integer, byval x2 as integer, byval y2 as integer, byval gl2dcolor as GLuint )

	glDisable( GL_TEXTURE_2D )
	glColor4ubv( cast( GLubyte ptr, @gl2dcolor ) )
    
    x2 += 1
    y2 += 1
    
	glBegin(GL_QUADS)
		
		glVertex2i	(x1,y1)
		glVertex2i	(x1,y2)
		glVertex2i	(x2,y2)
		glVertex2i	(x2,y1)
		
	glEnd()
	
	glEnable( GL_TEXTURE_2D )
	
	glColor4ub(255,255,255,255)
    
end sub


sub GL2D_Print_Scale(byval x as integer, byval y as integer, byval scale as single, byref text as const string)

   
   '' Only change active texture when there is a need
	'' Speeds up the rendering by batching textures
	if ( font_textureID <> current_texture ) then
		glBindTexture(GL_TEXTURE_2D, font_textureID)
		current_texture = font_textureID
	endif
	    
    glPushMatrix()
    glLoadIdentity()
    glTranslatef( x, y, 0 )
    glScalef(scale, scale, 1)
    glListBase( font_list_base )
        for i as integer = 0 to len(text) - 1
        	glCallList( font_list_base + text[i] )
        next i
    glPopMatrix()

end sub




VANYA
Posts: 1834
Joined: Oct 24, 2010 15:16
Location: Ярославль
Contact:

Re: The easiest way to code a 3d Platformer.

Post by VANYA »

Super!
Lachie Dazdarian
Posts: 2338
Joined: May 31, 2005 9:59
Location: Croatia
Contact:

Re: The easiest way to code a 3d Platformer.

Post by Lachie Dazdarian »

Wow! This is awesome! Thanks relsoft.

Would be great if you would take some time to present this in a form of a tutorial. Maybe add some code that enables easier level building. Like a map maker which is like any other 2D map maker (tile graphics is the front box texture), with one more option for each tile, and that is the background color or texture. Some of us are not good even with simple boxes in OpenGL.
relsoft
Posts: 1767
Joined: May 27, 2005 10:34
Location: Philippines
Contact:

Re: The easiest way to code a 3d Platformer.

Post by relsoft »

I'll try but almost all my free time is taken over by the DS side of coding and working out. ;*(
Lachie Dazdarian
Posts: 2338
Joined: May 31, 2005 9:59
Location: Croatia
Contact:

Re: The easiest way to code a 3d Platformer.

Post by Lachie Dazdarian »

Maybe if you can only show me how to assign a texture to a specific cube in the engine and front and back/side planes (or just change the color of back/side planes).

I can take care of the map editor then.
relsoft
Posts: 1767
Joined: May 27, 2005 10:34
Location: Philippines
Contact:

Re: The easiest way to code a 3d Platformer.

Post by relsoft »

Lachie Dazdarian wrote:Maybe if you can only show me how to assign a texture to a specific cube in the engine and front and back/side planes (or just change the color of back/side planes).

I can take care of the map editor then.
Here ya go:

http://rel.phatcode.net/junk.php?id=126

Map is text based so you can edit the level from inside code.
Code is now heavily commented.

Also added:

Code: Select all

1. A way to texture the level using a tileset
2. 3 camera scrolling behaviors
3. Parallax Background
4. Sprites
Images by Marc Russel from gfx-lib fuzed

DS screen:
Image
Lachie Dazdarian
Posts: 2338
Joined: May 31, 2005 9:59
Location: Croatia
Contact:

Re: The easiest way to code a 3d Platformer.

Post by Lachie Dazdarian »

Thanks a lot relsoft. This is really cool. Hopefully I'll be able to make something out of it.

Now about that GL2D.... :)

EDIT:

BTW, how do you distribute textures onto blocks in this version?
relsoft
Posts: 1767
Joined: May 27, 2005 10:34
Location: Philippines
Contact:

Re: The easiest way to code a 3d Platformer.

Post by relsoft »

Lachie Dazdarian wrote:Thanks a lot relsoft. This is really cool. Hopefully I'll be able to make something out of it.

Now about that GL2D.... :)

EDIT:

BTW, how do you distribute textures onto blocks in this version?
With the functions I ripped from Easy GL2D of course.

see:
Inittextures()
DrawMap()
ConvertMap()
VANYA
Posts: 1834
Joined: Oct 24, 2010 15:16
Location: Ярославль
Contact:

Re: The easiest way to code a 3d Platformer.

Post by VANYA »

Thank you. A great project!
relsoft
Posts: 1767
Joined: May 27, 2005 10:34
Location: Philippines
Contact:

Re: The easiest way to code a 3d Platformer.

Post by relsoft »

VANYA wrote:Thank you. A great project!
Thanks!
This can be anyone's project actually. I just shared it to the FB community.
Post Reply