summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/.gitignore1
-rw-r--r--examples/platformer/main.lua319
2 files changed, 319 insertions, 1 deletions
diff --git a/examples/.gitignore b/examples/.gitignore
deleted file mode 100644
index a1bb56d..0000000
--- a/examples/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-platformer \ No newline at end of file
diff --git a/examples/platformer/main.lua b/examples/platformer/main.lua
new file mode 100644
index 0000000..bc0023a
--- /dev/null
+++ b/examples/platformer/main.lua
@@ -0,0 +1,319 @@
+package.path = package.path..";"..RL_GetBasePath().."../resources/lib/?.lua"
+
+util = require "utillib"
+Vec2 = require "vector2"
+
+local TILE_SIZE = 16
+local PLAYER_MAXSPEED = 1.5
+local PLAYER_ACCELL = 5
+local PLAYER_DEACCELL = 5
+local GRAVITY = 6
+local JUMP_STR = 3
+local WALK_ANIM_SPEED = 8
+
+local tex = RL_LoadTexture( RL_GetBasePath().."../resources/images/arcade_platformerV2.png" )
+local res = Vec2:new( 160, 144 )
+local winScale = 5
+local winSize = res:scale( winScale )
+local framebuffer = RL_LoadRenderTexture( res )
+local monitor = 0
+local tilemap = {
+ size = Vec2:new( res.x / TILE_SIZE, res.y / TILE_SIZE ),
+ tiles = {},
+ tileRects = {
+ { 224, 112, TILE_SIZE, TILE_SIZE },
+ { 224, 48, TILE_SIZE, TILE_SIZE },
+ { 208, 48, TILE_SIZE, TILE_SIZE },
+ { 240, 48, TILE_SIZE, TILE_SIZE },
+ { 256, 96, TILE_SIZE, TILE_SIZE },
+ { 256, 112, TILE_SIZE, TILE_SIZE },
+ },
+}
+
+local player = {
+ vel = Vec2:new( 0, 0 ),
+ pos = Vec2:new( 32, 32 ), -- Center down.
+ colRect = { 0, 0, 12, 14 },
+ onFloor = false,
+ frames = {
+ { 6, 14, 20, 18 },
+ { 39, 14, 20, 18 },
+ { 70, 14, 20, 18 },
+ { 6, 45, 20, 18 },
+ { 38, 45, 20, 18 },
+ { 70, 45, 20, 18 },
+ },
+ walkAnimFrames = { 2, 3, 4, 3 },
+ curFrame = 1,
+ animPos = 0.0,
+ facing = 1,
+}
+
+local function createMap()
+ for x = 1, tilemap.size.x do
+ table.insert( tilemap.tiles, {} )
+
+ for y = 1, tilemap.size.y do
+ if y == tilemap.size.y then
+ table.insert( tilemap.tiles[x], 1 )
+ else
+ table.insert( tilemap.tiles[x], 0 )
+ end
+ end
+ end
+
+ tilemap.tiles[4][7] = 3
+ tilemap.tiles[5][7] = 2
+ tilemap.tiles[6][7] = 2
+ tilemap.tiles[7][7] = 4
+ tilemap.tiles[6][6] = 5
+
+ tilemap.tiles[10][4] = 5
+ tilemap.tiles[10][5] = 6
+ tilemap.tiles[10][6] = 6
+ tilemap.tiles[10][7] = 6
+ tilemap.tiles[10][8] = 6
+
+ tilemap.tiles[1][5] = 5
+ tilemap.tiles[1][6] = 6
+ tilemap.tiles[1][7] = 6
+ tilemap.tiles[1][8] = 6
+end
+
+function init()
+ local monitorPos = Vec2:new( RL_GetMonitorPosition( monitor ) )
+ local monitorSize = Vec2:new( RL_GetMonitorSize( monitor ) )
+
+ RL_SetWindowTitle( "Platformer" )
+ RL_SetWindowState( FLAG_WINDOW_RESIZABLE )
+ RL_SetWindowSize( winSize )
+ RL_SetWindowPosition( { monitorPos.x + monitorSize.x / 2 - winSize.x / 2, monitorPos.y + monitorSize.y / 2 - winSize.y / 2 } )
+
+ createMap()
+end
+
+local function isTileWall( pos )
+ if RL_CheckCollisionPointRec( { pos.x, pos.y }, { 0, 0, tilemap.size.x - 1, tilemap.size.y - 1 } ) then
+ return 0 < tilemap.tiles[ pos.x + 1 ][ pos.y + 1 ]
+ else
+ return false
+ end
+end
+
+local function tileCollision( entity )
+ local vPos = entity.pos + entity.vel -- Future pos with current vel.
+ local vRect = util.tableClone( entity.colRect )
+ local tinySlit = 0.001 -- Tiny slit between collisionRect and tile to prevent getting stuck on all seams.
+
+ -- Move test rect to predicted position.
+ vRect[1] = vPos.x - vRect[3] / 2
+
+ -- Tile range where collision box is affecting.
+ local tileRect = {
+ math.floor( vRect[1] / TILE_SIZE ),
+ math.floor( vRect[2] / TILE_SIZE ),
+ math.floor( ( vRect[1] + vRect[3] ) / TILE_SIZE ),
+ math.floor( ( vRect[2] + vRect[4] ) / TILE_SIZE ),
+ }
+
+ for y = tileRect[2], tileRect[4] do
+ if 0 < entity.vel.x then
+ if isTileWall( Vec2:new( tileRect[3], y ) ) then
+ -- Use new_x to push out of tile.
+ local new_x = tileRect[3] * TILE_SIZE - ( entity.colRect[1] + entity.colRect[3] )
+ entity.vel.x = new_x - tinySlit
+
+ break
+ end
+ elseif entity.vel.x < 0 then
+ if isTileWall( Vec2:new( tileRect[1], y ) ) then
+ local new_x = ( tileRect[1] * TILE_SIZE + TILE_SIZE ) - entity.colRect[1]
+ entity.vel.x = new_x + tinySlit, 0
+
+ break
+ end
+ end
+ end
+
+ -- Calculate new tileRect for y.
+ vRect[1] = entity.colRect[1] -- Reset to non predicted one.
+ vRect[2] = vPos.y - vRect[4]
+
+ tileRect = {
+ math.floor( vRect[1] / TILE_SIZE ),
+ math.floor( vRect[2] / TILE_SIZE ),
+ math.floor( ( vRect[1] + vRect[3] ) / TILE_SIZE ),
+ math.floor( ( vRect[2] + vRect[4] ) / TILE_SIZE ),
+ }
+
+ for x = tileRect[1], tileRect[3] do
+ if 0 < entity.vel.y then
+ if isTileWall( Vec2:new( x, tileRect[4] ) ) then
+ local new_y = tileRect[4] * TILE_SIZE - ( entity.colRect[2] + entity.colRect[4] )
+ -- math.max prevents bounce when hitting right on the corner.
+ entity.vel.y = math.max( new_y - tinySlit, 0 )
+ player.onFloor = true
+
+ break
+ end
+ elseif entity.vel.y < 0 then
+ if isTileWall( Vec2:new( x, tileRect[2] ) ) then
+ local new_y = ( tileRect[2] * TILE_SIZE + TILE_SIZE ) - entity.colRect[2]
+ entity.vel.y = new_y + tinySlit
+
+ break
+ end
+ end
+ end
+end
+
+local function playerMovement( delta )
+ local moving = { false, false }
+
+ if RL_IsKeyDown( KEY_RIGHT ) then
+ player.vel.x = player.vel.x + PLAYER_ACCELL * delta
+ moving[1] = true
+
+ if 0 < player.vel.x then
+ player.facing = 1
+ end
+ elseif RL_IsKeyDown( KEY_LEFT ) then
+ player.vel.x = player.vel.x - PLAYER_ACCELL * delta
+ moving[1] = true
+
+ if player.vel.x < 0 then
+ player.facing = -1
+ end
+ end
+
+ -- Alternative top down movement.
+
+ -- if RL_IsKeyDown( KEY_DOWN ) then
+ -- player.vel.y = player.vel.y + PLAYER_ACCELL * delta
+ -- moving[2] = true
+ -- elseif RL_IsKeyDown( KEY_UP ) then
+ -- player.vel.y = player.vel.y - PLAYER_ACCELL * delta
+ -- moving[2] = true
+ -- end
+
+ if RL_IsKeyPressed( KEY_SPACE ) and player.onFloor then
+ player.vel.y = -JUMP_STR
+ player.onFloor = false
+ end
+
+ -- Deaccel.
+
+ if not moving[1] then
+ if delta * PLAYER_DEACCELL < player.vel.x then
+ player.vel.x = player.vel.x - PLAYER_DEACCELL * delta
+ elseif player.vel.x < -delta * PLAYER_DEACCELL then
+ player.vel.x = player.vel.x + PLAYER_DEACCELL * delta
+ else
+ player.vel.x = 0.0
+ end
+ end
+
+ -- if not moving[2] then
+ -- if delta * PLAYER_DEACCELL < player.vel.y then
+ -- player.vel.y = player.vel.y - PLAYER_DEACCELL * delta
+ -- elseif player.vel.y < -delta * PLAYER_DEACCELL then
+ -- player.vel.y = player.vel.y + PLAYER_DEACCELL * delta
+ -- else
+ -- player.vel.y = 0.0
+ -- end
+ -- end
+
+ player.vel.x = util.clamp( player.vel.x, -PLAYER_MAXSPEED, PLAYER_MAXSPEED )
+ -- player.vel.y = util.clamp( player.vel.y, -PLAYER_MAXSPEED, PLAYER_MAXSPEED )
+
+ player.vel.y = player.vel.y + GRAVITY * delta
+
+ -- Drop from platform.
+ if player.onFloor and 0.5 < player.vel.y then
+ player.onFloor = false
+ end
+
+ tileCollision( player )
+ player.pos = player.pos + player.vel
+ player.colRect[1] = player.pos.x - player.colRect[3] / 2
+ player.colRect[2] = player.pos.y - player.colRect[4]
+end
+
+function process( delta )
+ if RL_IsWindowResized() then
+ winSize:set( RL_GetWindowSize() )
+ end
+
+ playerMovement( delta )
+end
+
+local function drawMap()
+ RL_DrawTextureRec( tex, { 0, 160, res.x, res.y }, { 0, 0 }, WHITE )
+
+ for x = 1, tilemap.size.x do
+ for y = 1, tilemap.size.y do
+ local tile = tilemap.tiles[x][y]
+ local pos = Vec2:new( x - 1, y - 1 )
+
+ if 0 < tile then
+ RL_DrawTextureRec( tex, tilemap.tileRects[ tile ], { pos.x * TILE_SIZE, pos.y * TILE_SIZE }, WHITE )
+ end
+ end
+ end
+end
+
+local function drawPlayer()
+ -- Animation.
+
+ if player.onFloor then
+ if math.abs( player.vel.x ) < 0.1 then
+ player.curFrame = 1
+ else
+ player.animPos = player.animPos + WALK_ANIM_SPEED * math.abs( player.vel.x ) * RL_GetFrameTime()
+ local frame = math.ceil( player.animPos )
+
+ if #player.walkAnimFrames < frame then
+ frame = 1
+ player.animPos = player.animPos - #player.walkAnimFrames
+ end
+
+ player.curFrame = frame
+ end
+ else
+ if 0 < player.vel.y then
+ player.curFrame = 6
+ elseif player.vel.y < 0 then
+ player.curFrame = 5
+ end
+ end
+
+ -- Draw rect.
+
+ local src = util.tableClone( player.frames[ player.curFrame ] )
+ local dst = {
+ player.pos.x - src[3] / 2,
+ player.pos.y - src[4],
+ src[3],
+ src[4],
+ }
+
+ if player.facing < 0 then
+ src[3] = -src[3]
+ end
+
+ RL_DrawTexturePro( tex, src, dst, { 0, 0 }, 0.0, WHITE )
+end
+
+function draw()
+ RL_ClearBackground( BLACK )
+
+ RL_SetTextureSource( TEXTURE_SOURCE_TEXTURE )
+ RL_BeginTextureMode( framebuffer )
+ drawMap()
+ drawPlayer()
+ RL_EndTextureMode()
+
+ RL_SetTextureSource( TEXTURE_SOURCE_RENDER_TEXTURE )
+ RL_DrawTexturePro( framebuffer, { 0, 0, res.x, -res.y }, { 0, 0, winSize.x, winSize.y }, { 0, 0 }, 0.0, WHITE )
+ RL_SetTextureSource( TEXTURE_SOURCE_TEXTURE )
+end