Lightmap 100 and 120 shaders. Snake and platformer example refining.
This commit is contained in:
@@ -208,6 +208,10 @@ CC= gcc
|
|||||||
# to
|
# to
|
||||||
CC= emcc
|
CC= emcc
|
||||||
|
|
||||||
|
CFLAGS= -Wall -O2 $(MYCFLAGS) -fno-stack-protector -fno-common -march=native
|
||||||
|
# to
|
||||||
|
CFLAGS= -Wall -O2 $(MYCFLAGS) -fno-stack-protector -fno-common
|
||||||
|
|
||||||
AR= ar rc
|
AR= ar rc
|
||||||
# to
|
# to
|
||||||
AR= emar
|
AR= emar
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ Cam3D = require( "camera3d" )
|
|||||||
|
|
||||||
local PLANE_SIZE = 8
|
local PLANE_SIZE = 8
|
||||||
|
|
||||||
|
local GLSL_VERSION = "330" -- PLATFORM_DESKTOP
|
||||||
|
-- local GLSL_VERSION = "100" -- PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB
|
||||||
|
|
||||||
local monitor = 0
|
local monitor = 0
|
||||||
local camera = {}
|
local camera = {}
|
||||||
local tileTexture = nil
|
local tileTexture = nil
|
||||||
@@ -52,10 +55,8 @@ function RL.init()
|
|||||||
lightmap = RL.LoadTexture( RL.GetBasePath().."../resources/images/lightmap.png" )
|
lightmap = RL.LoadTexture( RL.GetBasePath().."../resources/images/lightmap.png" )
|
||||||
RL.SetTextureFilter( lightmap, RL.TEXTURE_FILTER_TRILINEAR )
|
RL.SetTextureFilter( lightmap, RL.TEXTURE_FILTER_TRILINEAR )
|
||||||
|
|
||||||
shader = RL.LoadShader( RL.GetBasePath().."../resources/shaders/glsl330/lightmap.vs",
|
shader = RL.LoadShader( RL.GetBasePath().."../resources/shaders/glsl"..GLSL_VERSION.."/lightmap.vs",
|
||||||
RL.GetBasePath().."../resources/shaders/glsl330/lightmap.fs" )
|
RL.GetBasePath().."../resources/shaders/glsl"..GLSL_VERSION.."/lightmap.fs" )
|
||||||
|
|
||||||
print( "shader", shader )
|
|
||||||
|
|
||||||
local materialData = {
|
local materialData = {
|
||||||
shader = shader,
|
shader = shader,
|
||||||
@@ -79,7 +80,6 @@ function RL.init()
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
material = RL.CreateMaterial( materialData )
|
material = RL.CreateMaterial( materialData )
|
||||||
|
|
||||||
matrix = RL.MatrixMultiply( RL.MatrixIdentity(), RL.MatrixTranslate( { -4, 0, -4 } ) )
|
matrix = RL.MatrixMultiply( RL.MatrixIdentity(), RL.MatrixTranslate( { -4, 0, -4 } ) )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package.path = package.path..";"..RL.GetBasePath().."../resources/lib/?.lua"
|
|||||||
|
|
||||||
Util = require( "utillib" )
|
Util = require( "utillib" )
|
||||||
Vec2 = require( "vector2" )
|
Vec2 = require( "vector2" )
|
||||||
|
Rect = require( "rectangle" )
|
||||||
|
|
||||||
local TILE_SIZE = 16
|
local TILE_SIZE = 16
|
||||||
local PLAYER_MAXSPEED = 1.5
|
local PLAYER_MAXSPEED = 1.5
|
||||||
@@ -21,27 +22,26 @@ local tilemap = {
|
|||||||
size = Vec2:new( res.x / TILE_SIZE, res.y / TILE_SIZE ),
|
size = Vec2:new( res.x / TILE_SIZE, res.y / TILE_SIZE ),
|
||||||
tiles = {},
|
tiles = {},
|
||||||
tileRects = {
|
tileRects = {
|
||||||
{ 224, 112, TILE_SIZE, TILE_SIZE },
|
Rect:new( 224, 112, TILE_SIZE, TILE_SIZE ),
|
||||||
{ 224, 48, TILE_SIZE, TILE_SIZE },
|
Rect:new( 224, 48, TILE_SIZE, TILE_SIZE ),
|
||||||
{ 208, 48, TILE_SIZE, TILE_SIZE },
|
Rect:new( 208, 48, TILE_SIZE, TILE_SIZE ),
|
||||||
{ 240, 48, TILE_SIZE, TILE_SIZE },
|
Rect:new( 240, 48, TILE_SIZE, TILE_SIZE ),
|
||||||
{ 256, 96, TILE_SIZE, TILE_SIZE },
|
Rect:new( 256, 96, TILE_SIZE, TILE_SIZE ),
|
||||||
{ 256, 112, TILE_SIZE, TILE_SIZE },
|
Rect:new( 256, 112, TILE_SIZE, TILE_SIZE ),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
local player = {
|
local player = {
|
||||||
vel = Vec2:new( 0, 0 ),
|
vel = Vec2:new( 0, 0 ),
|
||||||
pos = Vec2:new( 32, 32 ), -- Center bottom.
|
pos = Vec2:new( 32, 32 ), -- Center bottom.
|
||||||
colRect = { 0, 0, 12, 14 },
|
colRect = Rect:new( 0, 0, 12, 14 ),
|
||||||
onFloor = false,
|
onFloor = false,
|
||||||
frames = {
|
frames = {
|
||||||
{ 6, 14, 20, 18 },
|
Rect:new( 6, 14, 20, 18 ),
|
||||||
{ 39, 13, 20, 19 },
|
Rect:new( 39, 13, 20, 19 ),
|
||||||
{ 70, 14, 20, 18 },
|
Rect:new( 70, 14, 20, 18 ),
|
||||||
{ 6, 45, 20, 18 },
|
Rect:new( 6, 45, 20, 18 ),
|
||||||
{ 38, 45, 20, 18 },
|
Rect:new( 38, 45, 20, 18 ),
|
||||||
{ 70, 45, 20, 18 },
|
Rect:new( 70, 45, 20, 18 ),
|
||||||
},
|
},
|
||||||
walkAnimFrames = { 2, 3, 4, 3 },
|
walkAnimFrames = { 2, 3, 4, 3 },
|
||||||
curFrame = 1,
|
curFrame = 1,
|
||||||
@@ -103,33 +103,33 @@ end
|
|||||||
|
|
||||||
local function tileCollision( entity )
|
local function tileCollision( entity )
|
||||||
local vPos = entity.pos + entity.vel -- Future pos with current vel.
|
local vPos = entity.pos + entity.vel -- Future pos with current vel.
|
||||||
local vRect = Util.tableClone( entity.colRect )
|
local vRect = entity.colRect:clone()
|
||||||
local tinyGap = 0.001 -- Tiny gap between collisionRect and tile to prevent getting stuck on all seams.
|
local tinyGap = 0.001 -- Tiny gap between collisionRect and tile to prevent getting stuck on all seams.
|
||||||
|
|
||||||
-- Move test rect to predicted position.
|
-- Move test rect to predicted position.
|
||||||
vRect[1] = vPos.x - vRect[3] / 2
|
vRect.x = vPos.x - vRect.width / 2
|
||||||
|
|
||||||
-- Tile range where collision box is affecting.
|
-- Tile range where collision box is affecting.
|
||||||
local tileRect = {
|
local tileRect = Rect:new(
|
||||||
math.floor( vRect[1] / TILE_SIZE ),
|
math.floor( vRect.x / TILE_SIZE ),
|
||||||
math.floor( vRect[2] / TILE_SIZE ),
|
math.floor( vRect.y / TILE_SIZE ),
|
||||||
math.floor( ( vRect[1] + vRect[3] ) / TILE_SIZE ),
|
math.floor( ( vRect.x + vRect.width ) / TILE_SIZE ),
|
||||||
math.floor( ( vRect[2] + vRect[4] ) / TILE_SIZE ),
|
math.floor( ( vRect.y + vRect.height ) / TILE_SIZE )
|
||||||
}
|
)
|
||||||
|
|
||||||
for y = tileRect[2], tileRect[4] do
|
for y = tileRect.y, tileRect.height do
|
||||||
if 0 < entity.vel.x then
|
if 0 < entity.vel.x then
|
||||||
if isTileWall( Vec2:new( tileRect[3], y ) ) then
|
if isTileWall( Vec2:new( tileRect.width, y ) ) then
|
||||||
-- Use new_x to push out of tile.
|
-- Use new_x to push out of tile.
|
||||||
local new_x = tileRect[3] * TILE_SIZE - ( entity.colRect[1] + entity.colRect[3] )
|
local new_x = tileRect.width * TILE_SIZE - ( entity.colRect.x + entity.colRect.width )
|
||||||
|
|
||||||
entity.vel.x = new_x - tinyGap
|
entity.vel.x = new_x - tinyGap
|
||||||
|
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
elseif entity.vel.x < 0 then
|
elseif entity.vel.x < 0 then
|
||||||
if isTileWall( Vec2:new( tileRect[1], y ) ) then
|
if isTileWall( Vec2:new( tileRect.x, y ) ) then
|
||||||
local new_x = ( tileRect[1] * TILE_SIZE + TILE_SIZE ) - entity.colRect[1]
|
local new_x = ( tileRect.x * TILE_SIZE + TILE_SIZE ) - entity.colRect.x
|
||||||
entity.vel.x = new_x + tinyGap
|
entity.vel.x = new_x + tinyGap
|
||||||
|
|
||||||
break
|
break
|
||||||
@@ -138,20 +138,20 @@ local function tileCollision( entity )
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Calculate new tileRect for y.
|
-- Calculate new tileRect for y.
|
||||||
vRect[1] = entity.colRect[1] -- Reset to non predicted one.
|
vRect.x = entity.colRect.x -- Reset to non predicted one.
|
||||||
vRect[2] = vPos.y - vRect[4]
|
vRect.y = vPos.y - vRect.height
|
||||||
|
|
||||||
tileRect = {
|
tileRect:set(
|
||||||
math.floor( vRect[1] / TILE_SIZE ),
|
math.floor( vRect.x / TILE_SIZE ),
|
||||||
math.floor( vRect[2] / TILE_SIZE ),
|
math.floor( vRect.y / TILE_SIZE ),
|
||||||
math.floor( ( vRect[1] + vRect[3] ) / TILE_SIZE ),
|
math.floor( ( vRect.x + vRect.width ) / TILE_SIZE ),
|
||||||
math.floor( ( vRect[2] + vRect[4] ) / TILE_SIZE ),
|
math.floor( ( vRect.y + vRect.height ) / TILE_SIZE )
|
||||||
}
|
)
|
||||||
|
|
||||||
for x = tileRect[1], tileRect[3] do
|
for x = tileRect.x, tileRect.width do
|
||||||
if 0 < entity.vel.y then
|
if 0 < entity.vel.y then
|
||||||
if isTileWall( Vec2:new( x, tileRect[4] ) ) then
|
if isTileWall( Vec2:new( x, tileRect.height ) ) then
|
||||||
local new_y = tileRect[4] * TILE_SIZE - ( entity.colRect[2] + entity.colRect[4] )
|
local new_y = tileRect.height * TILE_SIZE - ( entity.colRect.y + entity.colRect.height )
|
||||||
-- math.max prevents bounce when hitting right on the corner.
|
-- math.max prevents bounce when hitting right on the corner.
|
||||||
entity.vel.y = math.max( new_y - tinyGap, 0 )
|
entity.vel.y = math.max( new_y - tinyGap, 0 )
|
||||||
player.onFloor = true
|
player.onFloor = true
|
||||||
@@ -159,8 +159,8 @@ local function tileCollision( entity )
|
|||||||
break
|
break
|
||||||
end
|
end
|
||||||
elseif entity.vel.y < 0 then
|
elseif entity.vel.y < 0 then
|
||||||
if isTileWall( Vec2:new( x, tileRect[2] ) ) then
|
if isTileWall( Vec2:new( x, tileRect.y ) ) then
|
||||||
local new_y = ( tileRect[2] * TILE_SIZE + TILE_SIZE ) - entity.colRect[2]
|
local new_y = ( tileRect.y * TILE_SIZE + TILE_SIZE ) - entity.colRect.y
|
||||||
entity.vel.y = new_y + tinyGap
|
entity.vel.y = new_y + tinyGap
|
||||||
|
|
||||||
break
|
break
|
||||||
@@ -216,8 +216,8 @@ local function playerMovement( delta )
|
|||||||
|
|
||||||
tileCollision( player )
|
tileCollision( player )
|
||||||
player.pos = player.pos + player.vel
|
player.pos = player.pos + player.vel
|
||||||
player.colRect[1] = player.pos.x - player.colRect[3] / 2
|
player.colRect.x = player.pos.x - player.colRect.width / 2
|
||||||
player.colRect[2] = player.pos.y - player.colRect[4]
|
player.colRect.y = player.pos.y - player.colRect.height
|
||||||
end
|
end
|
||||||
|
|
||||||
function RL.process( delta )
|
function RL.process( delta )
|
||||||
@@ -270,16 +270,16 @@ local function drawPlayer()
|
|||||||
|
|
||||||
-- Draw rect.
|
-- Draw rect.
|
||||||
|
|
||||||
local src = Util.tableClone( player.frames[ player.curFrame ] )
|
local src = player.frames[ player.curFrame ]:clone()
|
||||||
local dst = {
|
local dst = Rect:new(
|
||||||
player.pos.x - src[3] / 2,
|
player.pos.x - src.width / 2,
|
||||||
player.pos.y - src[4],
|
player.pos.y - src.height,
|
||||||
src[3],
|
src.width,
|
||||||
src[4],
|
src.height
|
||||||
}
|
)
|
||||||
|
|
||||||
if player.facing < 0 then
|
if player.facing < 0 then
|
||||||
src[3] = -src[3]
|
src.width = -src.width
|
||||||
end
|
end
|
||||||
|
|
||||||
RL.DrawTexturePro( tex, src, dst, { 0, 0 }, 0.0, RL.WHITE )
|
RL.DrawTexturePro( tex, src, dst, { 0, 0 }, 0.0, RL.WHITE )
|
||||||
@@ -293,5 +293,12 @@ function RL.draw()
|
|||||||
drawPlayer()
|
drawPlayer()
|
||||||
RL.EndTextureMode()
|
RL.EndTextureMode()
|
||||||
|
|
||||||
RL.DrawTexturePro( RL.GetRenderTextureTexture( framebuffer ), { 0, 0, res.x, -res.y }, { 0, 0, winSize.x, winSize.y }, { 0, 0 }, 0.0, RL.WHITE )
|
RL.DrawTexturePro(
|
||||||
|
RL.GetRenderTextureTexture( framebuffer ),
|
||||||
|
{ 0, 0, res.x, -res.y },
|
||||||
|
{ 0, 0, winSize.x, winSize.y },
|
||||||
|
{ 0, 0 },
|
||||||
|
0.0,
|
||||||
|
RL.WHITE
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|||||||
22
examples/resources/shaders/glsl100/lightmap.fs
Normal file
22
examples/resources/shaders/glsl100/lightmap.fs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#version 100
|
||||||
|
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
// Input vertex attributes (from vertex shader)
|
||||||
|
varying vec2 fragTexCoord;
|
||||||
|
varying vec2 fragTexCoord2;
|
||||||
|
varying vec3 fragPosition;
|
||||||
|
varying vec4 fragColor;
|
||||||
|
|
||||||
|
// Input uniform values
|
||||||
|
uniform sampler2D texture0;
|
||||||
|
uniform sampler2D texture1;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// Texel color fetching from texture sampler
|
||||||
|
vec4 texelColor = texture2D(texture0, fragTexCoord);
|
||||||
|
vec4 texelColor2 = texture2D(texture1, fragTexCoord2);
|
||||||
|
|
||||||
|
gl_FragColor = texelColor * texelColor2;
|
||||||
|
}
|
||||||
31
examples/resources/shaders/glsl100/lightmap.vs
Normal file
31
examples/resources/shaders/glsl100/lightmap.vs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#version 100
|
||||||
|
|
||||||
|
// Input vertex attributes
|
||||||
|
attribute vec3 vertexPosition;
|
||||||
|
attribute vec2 vertexTexCoord;
|
||||||
|
attribute vec2 vertexTexCoord2;
|
||||||
|
attribute vec4 vertexColor;
|
||||||
|
|
||||||
|
// Input uniform values
|
||||||
|
uniform mat4 mvp;
|
||||||
|
uniform mat4 matModel;
|
||||||
|
|
||||||
|
// Output vertex attributes (to fragment shader)
|
||||||
|
varying vec3 fragPosition;
|
||||||
|
varying vec2 fragTexCoord;
|
||||||
|
varying vec2 fragTexCoord2;
|
||||||
|
varying vec4 fragColor;
|
||||||
|
|
||||||
|
// NOTE: Add here your custom variables
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// Send vertex attributes to fragment shader
|
||||||
|
fragPosition = vec3(matModel*vec4(vertexPosition, 1.0));
|
||||||
|
fragTexCoord = vertexTexCoord;
|
||||||
|
fragTexCoord2 = vertexTexCoord2;
|
||||||
|
fragColor = vertexColor;
|
||||||
|
|
||||||
|
// Calculate final vertex position
|
||||||
|
gl_Position = mvp*vec4(vertexPosition, 1.0);
|
||||||
|
}
|
||||||
20
examples/resources/shaders/glsl120/lightmap.fs
Normal file
20
examples/resources/shaders/glsl120/lightmap.fs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#version 120
|
||||||
|
|
||||||
|
// Input vertex attributes (from vertex shader)
|
||||||
|
varying vec2 fragTexCoord;
|
||||||
|
varying vec2 fragTexCoord2;
|
||||||
|
varying vec3 fragPosition;
|
||||||
|
varying vec4 fragColor;
|
||||||
|
|
||||||
|
// Input uniform values
|
||||||
|
uniform sampler2D texture0;
|
||||||
|
uniform sampler2D texture1;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// Texel color fetching from texture sampler
|
||||||
|
vec4 texelColor = texture2D(texture0, fragTexCoord);
|
||||||
|
vec4 texelColor2 = texture2D(texture1, fragTexCoord2);
|
||||||
|
|
||||||
|
gl_FragColor = texelColor * texelColor2;
|
||||||
|
}
|
||||||
31
examples/resources/shaders/glsl120/lightmap.vs
Normal file
31
examples/resources/shaders/glsl120/lightmap.vs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#version 120
|
||||||
|
|
||||||
|
// Input vertex attributes
|
||||||
|
attribute vec3 vertexPosition;
|
||||||
|
attribute vec2 vertexTexCoord;
|
||||||
|
attribute vec2 vertexTexCoord2;
|
||||||
|
attribute vec4 vertexColor;
|
||||||
|
|
||||||
|
// Input uniform values
|
||||||
|
uniform mat4 mvp;
|
||||||
|
uniform mat4 matModel;
|
||||||
|
|
||||||
|
// Output vertex attributes (to fragment shader)
|
||||||
|
varying vec3 fragPosition;
|
||||||
|
varying vec2 fragTexCoord;
|
||||||
|
varying vec2 fragTexCoord2;
|
||||||
|
varying vec4 fragColor;
|
||||||
|
|
||||||
|
// NOTE: Add here your custom variables
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// Send vertex attributes to fragment shader
|
||||||
|
fragPosition = vec3(matModel*vec4(vertexPosition, 1.0));
|
||||||
|
fragTexCoord = vertexTexCoord;
|
||||||
|
fragTexCoord2 = vertexTexCoord2;
|
||||||
|
fragColor = vertexColor;
|
||||||
|
|
||||||
|
// Calculate final vertex position
|
||||||
|
gl_Position = mvp*vec4(vertexPosition, 1.0);
|
||||||
|
}
|
||||||
@@ -1,16 +1,21 @@
|
|||||||
|
package.path = package.path..";"..RL.GetBasePath().."../resources/lib/?.lua"
|
||||||
|
|
||||||
|
Vec2 = require( "vector2" )
|
||||||
|
Rect = require( "rectangle" )
|
||||||
|
|
||||||
-- Defines
|
-- Defines
|
||||||
local RESOLUTION = { 128, 128 }
|
local RESOLUTION = Vec2:new( 128, 128 )
|
||||||
local TILE_SIZE = 8
|
local TILE_SIZE = 8
|
||||||
local LEVEL_SIZE = RESOLUTION[1] / TILE_SIZE
|
local LEVEL_SIZE = RESOLUTION.x / TILE_SIZE
|
||||||
local STATE = { TITLE = 0, GAME = 1, OVER = 2 } -- Enum wannabe.
|
local STATE = { TITLE = 0, GAME = 1, OVER = 2 } -- Enum.
|
||||||
|
|
||||||
-- Resources
|
-- Resources
|
||||||
local framebuffer = nil
|
local framebuffer = nil
|
||||||
local monitor = 0
|
local monitor = 0
|
||||||
local monitorPos = RL.GetMonitorPosition( monitor )
|
local monitorPos = Vec2:new( RL.GetMonitorPosition( monitor ) )
|
||||||
local monitorSize = RL.GetMonitorSize( monitor )
|
local monitorSize = Vec2:new( RL.GetMonitorSize( monitor ) )
|
||||||
local winScale = 6
|
local winScale = 6
|
||||||
local winSize = { RESOLUTION[1] * winScale, RESOLUTION[2] * winScale }
|
local winSize = Vec2:new( RESOLUTION.x * winScale, RESOLUTION.y * winScale )
|
||||||
local gameState = STATE.GAME
|
local gameState = STATE.GAME
|
||||||
local grassTexture = -1
|
local grassTexture = -1
|
||||||
local snakeTexture = -1
|
local snakeTexture = -1
|
||||||
@@ -22,38 +27,39 @@ local applePos = {}
|
|||||||
|
|
||||||
local function setSnake()
|
local function setSnake()
|
||||||
snake = {
|
snake = {
|
||||||
heading = { 1, 0 },
|
heading = Vec2:new( 1, 0 ),
|
||||||
control = { 1, 0 },
|
control = Vec2:new( 1, 0 ),
|
||||||
headPos = { LEVEL_SIZE / 2, LEVEL_SIZE / 2 },
|
headPos = Vec2:new( LEVEL_SIZE / 2, LEVEL_SIZE / 2 ),
|
||||||
segments = {},
|
segments = {}, -- { pos Vec2, heading Vec2 }
|
||||||
grow = 2,
|
grow = 2,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
local function vector2IsEqual( v1, v2 )
|
|
||||||
return v1[1] == v2[1] and v1[2] == v2[2]
|
|
||||||
end
|
|
||||||
|
|
||||||
local function addSegment()
|
local function addSegment()
|
||||||
-- If first segment, grow from head and otherwise from tail. New segments are inserted firts.
|
-- If first segment, grow from head and otherwise from tail. New segments are inserted firts.
|
||||||
if #snake.segments == 0 then
|
if #snake.segments == 0 then
|
||||||
table.insert( snake.segments, 1, { pos = snake.headPos, heading = snake.heading } )
|
table.insert( snake.segments, 1, {
|
||||||
|
pos = snake.headPos:clone(),
|
||||||
|
heading = snake.heading:clone()
|
||||||
|
} )
|
||||||
else
|
else
|
||||||
table.insert( snake.segments, 1, { pos = snake.segments[ #snake.segments ].pos,
|
table.insert( snake.segments, 1, {
|
||||||
heading = snake.segments[ #snake.segments ].heading } )
|
pos = snake.segments[ #snake.segments ].pos:clone(),
|
||||||
|
heading = snake.segments[ #snake.segments ].heading:clone()
|
||||||
|
} )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function setApplePos()
|
local function setApplePos()
|
||||||
applePos = { math.random( 0, LEVEL_SIZE - 1 ), math.random( 0, LEVEL_SIZE - 1 ) }
|
applePos = Vec2:new( math.random( 0, LEVEL_SIZE - 1 ), math.random( 0, LEVEL_SIZE - 1 ) )
|
||||||
local search = true
|
local search = true
|
||||||
|
|
||||||
while search do
|
while search do
|
||||||
search = false
|
search = false
|
||||||
applePos = { math.random( 0, LEVEL_SIZE - 1 ), math.random( 0, LEVEL_SIZE - 1 ) }
|
applePos = Vec2:new( math.random( 0, LEVEL_SIZE - 1 ), math.random( 0, LEVEL_SIZE - 1 ) )
|
||||||
|
|
||||||
for _, seg in ipairs( snake.segments ) do
|
for _, seg in ipairs( snake.segments ) do
|
||||||
search = vector2IsEqual( applePos, seg.pos )
|
search = applePos == seg.pos
|
||||||
|
|
||||||
if search then
|
if search then
|
||||||
break
|
break
|
||||||
@@ -68,7 +74,7 @@ function RL.init()
|
|||||||
RL.SetWindowState( RL.FLAG_WINDOW_RESIZABLE )
|
RL.SetWindowState( RL.FLAG_WINDOW_RESIZABLE )
|
||||||
RL.SetWindowState( RL.FLAG_VSYNC_HINT )
|
RL.SetWindowState( RL.FLAG_VSYNC_HINT )
|
||||||
RL.SetWindowSize( winSize )
|
RL.SetWindowSize( winSize )
|
||||||
RL.SetWindowPosition( { monitorPos[1] + monitorSize[1] / 2 - winSize[1] / 2, monitorPos[2] + monitorSize[2] / 2 - winSize[2] / 2 } )
|
RL.SetWindowPosition( { monitorPos.x + monitorSize.x / 2 - winSize.x / 2, monitorPos.y + monitorSize.y / 2 - winSize.y / 2 } )
|
||||||
RL.SetWindowTitle( "Snake" )
|
RL.SetWindowTitle( "Snake" )
|
||||||
RL.SetWindowIcon( RL.LoadImage( RL.GetBasePath().."../resources/images/apple.png" ) )
|
RL.SetWindowIcon( RL.LoadImage( RL.GetBasePath().."../resources/images/apple.png" ) )
|
||||||
|
|
||||||
@@ -92,30 +98,30 @@ local function moveSnake()
|
|||||||
-- Move body.
|
-- Move body.
|
||||||
for i, seg in ipairs( snake.segments ) do
|
for i, seg in ipairs( snake.segments ) do
|
||||||
if i < #snake.segments then
|
if i < #snake.segments then
|
||||||
seg.pos = snake.segments[ i+1 ].pos
|
seg.pos = snake.segments[ i+1 ].pos:clone()
|
||||||
seg.heading = snake.segments[ i+1 ].heading
|
seg.heading = snake.segments[ i+1 ].heading:clone()
|
||||||
else
|
else
|
||||||
seg.pos = snake.headPos
|
seg.pos = snake.headPos:clone()
|
||||||
seg.heading = snake.heading
|
seg.heading = snake.heading:clone()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- Move head.
|
-- Move head.
|
||||||
snake.heading = { snake.control[1], snake.control[2] }
|
snake.heading = Vec2:new( snake.control.x, snake.control.y )
|
||||||
snake.headPos = { snake.headPos[1] + snake.heading[1], snake.headPos[2] + snake.heading[2] }
|
snake.headPos = Vec2:new( snake.headPos.x + snake.heading.x, snake.headPos.y + snake.heading.y )
|
||||||
|
|
||||||
-- Check appple eating.
|
-- Check appple eating.
|
||||||
if vector2IsEqual( snake.headPos, applePos ) then
|
if snake.headPos == applePos then
|
||||||
snake.grow = snake.grow + 1
|
snake.grow = snake.grow + 1
|
||||||
setApplePos()
|
setApplePos()
|
||||||
end
|
end
|
||||||
-- Check if hit to body.
|
-- Check if hit to body.
|
||||||
for _, seg in ipairs( snake.segments ) do
|
for _, seg in ipairs( snake.segments ) do
|
||||||
if vector2IsEqual( snake.headPos, seg.pos ) then
|
if snake.headPos == seg.pos then
|
||||||
gameState = STATE.OVER
|
gameState = STATE.OVER
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- Check if outside or level.
|
-- Check if outside or level.
|
||||||
if snake.headPos[1] < 0 or LEVEL_SIZE <= snake.headPos[1] or snake.headPos[2] < 0 or LEVEL_SIZE <= snake.headPos[2] then
|
if snake.headPos.x < 0 or LEVEL_SIZE <= snake.headPos.x or snake.headPos.y < 0 or LEVEL_SIZE <= snake.headPos.y then
|
||||||
gameState = STATE.OVER
|
gameState = STATE.OVER
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -125,14 +131,14 @@ end
|
|||||||
function RL.process( delta )
|
function RL.process( delta )
|
||||||
if gameState == STATE.GAME then -- Run game.
|
if gameState == STATE.GAME then -- Run game.
|
||||||
-- Controls.
|
-- Controls.
|
||||||
if RL.IsKeyPressed( RL.KEY_RIGHT ) and 0 <= snake.heading[1] then
|
if RL.IsKeyPressed( RL.KEY_RIGHT ) and 0 <= snake.heading.x then
|
||||||
snake.control = { 1, 0 }
|
snake.control = Vec2:new( 1, 0 )
|
||||||
elseif RL.IsKeyPressed( RL.KEY_LEFT ) and snake.heading[1] <= 0 then
|
elseif RL.IsKeyPressed( RL.KEY_LEFT ) and snake.heading.x <= 0 then
|
||||||
snake.control = { -1, 0 }
|
snake.control = Vec2:new( -1, 0 )
|
||||||
elseif RL.IsKeyPressed( RL.KEY_DOWN ) and 0 <= snake.heading[2] then
|
elseif RL.IsKeyPressed( RL.KEY_DOWN ) and 0 <= snake.heading.y then
|
||||||
snake.control = { 0, 1 }
|
snake.control = Vec2:new( 0, 1 )
|
||||||
elseif RL.IsKeyPressed( RL.KEY_UP ) and snake.heading[2] <= 0 then
|
elseif RL.IsKeyPressed( RL.KEY_UP ) and snake.heading.y <= 0 then
|
||||||
snake.control = { 0, -1 }
|
snake.control = Vec2:new( 0, -1 )
|
||||||
end
|
end
|
||||||
|
|
||||||
moveTimer = moveTimer - gameSpeed * delta
|
moveTimer = moveTimer - gameSpeed * delta
|
||||||
@@ -160,46 +166,61 @@ end
|
|||||||
--[[ Check if next segment is on left side. There are more mathematically elegant solution to this, but there is
|
--[[ Check if next segment is on left side. There are more mathematically elegant solution to this, but there is
|
||||||
only four possibilities so we can just check them all. ]]--
|
only four possibilities so we can just check them all. ]]--
|
||||||
local function onLeft( this, nextSeg )
|
local function onLeft( this, nextSeg )
|
||||||
return ( vector2IsEqual( this, { 0, -1 } ) and vector2IsEqual( nextSeg, { -1, 0 } ) )
|
return ( this == Vec2:new( 0, -1 ) and nextSeg == Vec2:new( -1, 0 ) )
|
||||||
or ( vector2IsEqual( this, { -1, 0 } ) and vector2IsEqual( nextSeg, { 0, 1 } ) )
|
or ( this == Vec2:new( -1, 0 ) and nextSeg == Vec2:new( 0, 1 ) )
|
||||||
or ( vector2IsEqual( this, { 0, 1 } ) and vector2IsEqual( nextSeg, { 1, 0 } ) )
|
or ( this == Vec2:new( 0, 1 ) and nextSeg == Vec2:new( 1, 0 ) )
|
||||||
or ( vector2IsEqual( this, { 1, 0 } ) and vector2IsEqual( nextSeg, { 0, -1 } ) )
|
or ( this == Vec2:new( 1, 0 ) and nextSeg == Vec2:new( 0, -1 ) )
|
||||||
end
|
end
|
||||||
|
|
||||||
local function drawSnake()
|
local function drawSnake()
|
||||||
for i, seg in ipairs( snake.segments ) do
|
for i, seg in ipairs( snake.segments ) do
|
||||||
local angle = math.deg( RL.Vector2Angle( { 0, 0 }, seg.heading ) )
|
local angle = math.deg( RL.Vector2Angle( { 0, 0 }, seg.heading ) )
|
||||||
local source = { 16, 0, 8, 8 }
|
local source = Rect:new( 16, 0, 8, 8 )
|
||||||
|
|
||||||
if i == 1 then -- Tail segment. Yes tail is actually the 'first' segment.
|
if i == 1 then -- Tail segment. Yes tail is actually the 'first' segment.
|
||||||
source[1] = 8
|
source.x = 8
|
||||||
|
|
||||||
if 1 < #snake.segments then
|
if 1 < #snake.segments then
|
||||||
angle = math.deg( RL.Vector2Angle( { 0, 0 }, snake.segments[ 2 ].heading ) )
|
angle = math.deg( RL.Vector2Angle( { 0, 0 }, snake.segments[ 2 ].heading ) )
|
||||||
end
|
end
|
||||||
elseif i < #snake.segments and not vector2IsEqual( seg.heading, snake.segments[ i+1 ].heading ) then -- Turned middle segments.
|
elseif i < #snake.segments and seg.heading ~= snake.segments[ i+1 ].heading then -- Turned middle segments.
|
||||||
source[1] = 0
|
source.x = 0
|
||||||
-- Mirror turned segment to other way.
|
-- Mirror turned segment to other way.
|
||||||
if onLeft( seg.heading, snake.segments[ i+1 ].heading ) then
|
if onLeft( seg.heading, snake.segments[ i+1 ].heading ) then
|
||||||
source[4] = -8
|
source.height = -8
|
||||||
end
|
end
|
||||||
elseif i == #snake.segments and not vector2IsEqual( seg.heading, snake.heading ) then -- Turned segment before head.
|
elseif i == #snake.segments and seg.heading ~= snake.heading then -- Turned segment before head.
|
||||||
source[1] = 0
|
source.x = 0
|
||||||
|
|
||||||
if onLeft( seg.heading, snake.heading ) then
|
if onLeft( seg.heading, snake.heading ) then
|
||||||
source[4] = -8
|
source.height = -8
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- Notice that we set the origin to center { 4, 4 } that acts as pivot point. We also have to adjust our dest position by 4.
|
-- Notice that we set the origin to center { 4, 4 } that acts as pivot point. We also have to adjust our dest position by 4.
|
||||||
RL.DrawTexturePro( snakeTexture, source, { seg.pos[1] * TILE_SIZE + 4, seg.pos[2] * TILE_SIZE + 4, 8, 8 }, { 4, 4 }, angle, RL.WHITE )
|
RL.DrawTexturePro(
|
||||||
|
snakeTexture,
|
||||||
|
source,
|
||||||
|
{ seg.pos.x * TILE_SIZE + 4, seg.pos.y * TILE_SIZE + 4, 8, 8 },
|
||||||
|
{ 4, 4 },
|
||||||
|
angle,
|
||||||
|
RL.WHITE
|
||||||
|
)
|
||||||
end
|
end
|
||||||
-- Let's draw the head last to keep it on top.
|
-- Let's draw the head last to keep it on top.
|
||||||
local angle = math.deg( RL.Vector2Angle( { 0, 0 }, snake.heading ) )
|
local angle = math.deg( RL.Vector2Angle( { 0, 0 }, snake.heading ) )
|
||||||
RL.DrawTexturePro( snakeTexture, { 24, 0, 8, 8 }, { snake.headPos[1] * TILE_SIZE + 4, snake.headPos[2] * TILE_SIZE + 4, 8, 8 }, { 4, 4 }, angle, RL.WHITE )
|
RL.DrawTexturePro(
|
||||||
|
snakeTexture,
|
||||||
|
{ 24, 0, 8, 8 },
|
||||||
|
{ snake.headPos.x * TILE_SIZE + 4,
|
||||||
|
snake.headPos.y * TILE_SIZE + 4, 8, 8 },
|
||||||
|
{ 4, 4 },
|
||||||
|
angle,
|
||||||
|
RL.WHITE
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function drawApple()
|
local function drawApple()
|
||||||
RL.DrawTexture( appleTexture, { applePos[1] * TILE_SIZE, applePos[2] * TILE_SIZE }, RL.WHITE )
|
RL.DrawTexture( appleTexture, { applePos.x * TILE_SIZE, applePos.y * TILE_SIZE }, RL.WHITE )
|
||||||
end
|
end
|
||||||
|
|
||||||
function RL.draw()
|
function RL.draw()
|
||||||
@@ -218,5 +239,12 @@ function RL.draw()
|
|||||||
RL.EndTextureMode()
|
RL.EndTextureMode()
|
||||||
|
|
||||||
-- Draw framebuffer to window.
|
-- Draw framebuffer to window.
|
||||||
RL.DrawTexturePro( RL.GetRenderTextureTexture( framebuffer ), { 0, 0, RESOLUTION[1], -RESOLUTION[2] }, { 0, 0, winSize[1], winSize[2] }, { 0, 0 }, 0.0, RL.WHITE )
|
RL.DrawTexturePro(
|
||||||
|
RL.GetRenderTextureTexture( framebuffer ),
|
||||||
|
{ 0, 0, RESOLUTION.x, -RESOLUTION.y },
|
||||||
|
{ 0, 0, winSize.x, winSize.y },
|
||||||
|
{ 0, 0 },
|
||||||
|
0.0,
|
||||||
|
RL.WHITE
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user