diff options
| author | jussi | 2022-05-26 18:50:30 +0300 |
|---|---|---|
| committer | jussi | 2022-05-26 18:50:30 +0300 |
| commit | acad17965dee43816200b889f98f04f6ff80a939 (patch) | |
| tree | 958b95fa166ab0e4795c6dc856d4c6da4a43306d | |
| parent | 3aec701f80478e6d26f132486163b62451e3d0e9 (diff) | |
| download | reilua-enhanced-acad17965dee43816200b889f98f04f6ff80a939.tar.gz reilua-enhanced-acad17965dee43816200b889f98f04f6ff80a939.tar.bz2 reilua-enhanced-acad17965dee43816200b889f98f04f6ff80a939.zip | |
Platformer example.
| -rw-r--r-- | examples/.gitignore | 1 | ||||
| -rw-r--r-- | examples/platformer/main.lua | 319 |
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 |
