help slope platformer 2d

General discussion about LÖVE, Lua, game development, puns, and unicorns.
Post Reply
User avatar
luislasonbra
Citizen
Posts: 60
Joined: Sun Jun 24, 2012 1:57 pm

help slope platformer 2d

Post by luislasonbra »

hi

I'm trying to implement slope on my platform game.

I have already implemented the slope (left / right) and work well.

I have only one problem, when the player down the slope (left / right), this does not follow the slope.

I hope you can help me.

preview
Image

This is the code I use to check the slope:

Code: Select all

-- check if there is a collision with a slope
function checkForSlopes()
	--
	-- left slope.
	--
	local xtile = math.floor((player.x + ((tileMap.TileWidth / 2) - 2)) / tileMap.TileWidth);
	local ytile = math.floor((player.y) / tileMap.TileHeight);
	--
	local ylerp = (ytile * tileMap.TileHeight) - (player.x - (xtile * tileMap.TileWidth));
	if tileMap.map[ytile + 1][xtile] == 2 then ytile = ytile + 1; end
	if tileMap.map[ytile][xtile] == 2 and player.ySpeed >= 0 then
		--
		ylerp = (ytile * tileMap.TileHeight) - (player.x - (xtile * tileMap.TileWidth));
		if player.y >= ylerp then
			player.onFloor = true;
			--
			player.y = ylerp;
			player.ySpeed = 0;
		end
		--
	end
	--
	-- right slope.
	--
	xtile = math.floor((player.x - ((tileMap.TileWidth / 2) - 2)) / tileMap.TileWidth);
	ytile = math.floor((player.y) / tileMap.TileHeight);
	--
	if tileMap.map[ytile + 1][xtile] == 3 then ytile = ytile + 1; end
	if tileMap.map[ytile][xtile] == 3 and player.ySpeed >= 0 then
		--
		ylerp = (ytile * tileMap.TileHeight) - (tileMap.TileWidth - (player.x - (xtile * tileMap.TileWidth)));
		if player.y >= ylerp then
			player.onFloor = true;
			--
			player.y = ylerp;
			player.ySpeed = 0;
		end
		--
	end
	--
end
here is the code of the game so far.

Code: Select all

-- vector2
-- =====================================================================
vector2 = {};
vector2.new = function(...)
	local obj = {};
	local a, b = ...;
	--
	obj.x = a or 0;
	obj.y = b or 0;
	--
	return obj;
end
--
-- MathHelper
-- =====================================================================
function math.clamp(x, min, max)
	return x < min and min or (x > max and max or x)
end
--
-- draw Slopes and collision
-- =====================================================================
-- left slope
function drawslopeLeft(x0, y0, x1, y1)
	for i = 0, 32 do
		love.graphics.line(x0 + i, y0, x1, y1);
	end
end
-- right slope
function drawslopeRight(x0, y0, x1, y1)
	for i = 0, 32 do
		love.graphics.line(x0, y0 + i, x1, y1);
	end
end
--
-- check if there is a collision with a slope
function checkForSlopes()
	--
	-- left slope.
	--
	local xtile = math.floor((player.x + ((tileMap.TileWidth / 2) - 2)) / tileMap.TileWidth);
	local ytile = math.floor((player.y) / tileMap.TileHeight);
	--
	local ylerp = (ytile * tileMap.TileHeight) - (player.x - (xtile * tileMap.TileWidth));
	if tileMap.map[ytile + 1][xtile] == 2 then ytile = ytile + 1; end
	if tileMap.map[ytile][xtile] == 2 and player.ySpeed >= 0 then
		--
		ylerp = (ytile * tileMap.TileHeight) - (player.x - (xtile * tileMap.TileWidth));
		if player.y >= ylerp then
			player.onFloor = true;
			--
			player.y = ylerp;
			player.ySpeed = 0;
		end
		--
	end
	--
	-- right slope.
	--
	xtile = math.floor((player.x - ((tileMap.TileWidth / 2) - 2)) / tileMap.TileWidth);
	ytile = math.floor((player.y) / tileMap.TileHeight);
	--
	if tileMap.map[ytile + 1][xtile] == 3 then ytile = ytile + 1; end
	if tileMap.map[ytile][xtile] == 3 and player.ySpeed >= 0 then
		--
		ylerp = (ytile * tileMap.TileHeight) - (tileMap.TileWidth - (player.x - (xtile * tileMap.TileWidth)));
		if player.y >= ylerp then
			player.onFloor = true;
			--
			player.y = ylerp;
			player.ySpeed = 0;
		end
		--
	end
	--
end
--
-- player
-- =====================================================================
player = {};
function player.load()
	player.xSpeed = 0;
	player.ySpeed = 0;

	player.xSpeedMax = 800;
	player.ySpeedMax = 800;

	player.x = 4 * 32;
	player.y = 3 * 32;

	player.width = 32;
	player.height = 32;

	gravity = 2800;

	player.onFloor = false;
	player.runSpeed = 500;
	player.jumpSpeed = -800;
end

-- Movement functions
function player.jump()
    if player.onFloor then
        player.ySpeed = player.jumpSpeed;
        player.onFloor = false;
    end
end

function player.moveRight()
    player.xSpeed = player.runSpeed;
end

function player.moveLeft()
    player.xSpeed = -1 * player.runSpeed;
end

function player.stop()
    player.xSpeed = 0;
end

-- Do various things when the player hits a tile
function player:collide(event)
    if event == "floor" then
        player.ySpeed = 0;
        player.onFloor = true;
    end
    if event == "ceiling" then
        player.ySpeed = 0;
    end
end

function player.update(dt)
	local halfX = player.width / 2;
	local halfY = player.height / 2;

	-- apply gravity
    player.ySpeed = player.ySpeed + (gravity * dt);

	-- limit the player's speed
    player.xSpeed = math.clamp(player.xSpeed, -player.xSpeedMax, player.xSpeedMax);
    player.ySpeed = math.clamp(player.ySpeed, -player.ySpeedMax, player.ySpeedMax);

	-- calculate vertical position and adjust if needed
    local nextY = math.floor(player.y + (player.ySpeed * dt));
    if player.ySpeed < 0 then -- check upward
        if not(player.isColliding(player.x - halfX, nextY - halfY)) and not(player.isColliding(player.x + halfX - 1, nextY - halfY)) then
            -- no collision, move normally
            player.y = nextY;
            player.onFloor = false;
        else
            -- collision, move to nearest tile border
            player.y = nextY + map.tileHeight - ((nextY - halfY) % tileMap.TileHeight);
            player.collide("ceiling");
        end
    elseif player.ySpeed > 0 then -- check downward
        if not(player.isColliding(player.x - halfX, nextY + halfY)) and not(player.isColliding(player.x + halfX - 1, nextY + halfY)) then
            -- no collision, move normally
            player.y = nextY;
            player.onFloor = false;
        else
            -- collision, move to nearest tile border
            player.y = nextY - ((nextY + halfY) % tileMap.TileHeight);
            player:collide("floor");
        end
    end

    -- calculate horizontal position and adjust if needed
    local nextX = math.floor(player.x + (player.xSpeed * dt));
    if player.xSpeed > 0 then -- check right
        if not(player.isColliding(nextX + halfX, player.y - halfY))
            and not(player.isColliding(nextX + halfX, player.y + halfY - 1)) then
            -- no collision
            player.x = nextX;
        else
            -- collision, move to nearest tile
            player.x = nextX - ((nextX + halfX) % tileMap.TileWidth);
        end
    elseif player.xSpeed < 0 then -- check left
        if not(player.isColliding(nextX - halfX, player.y - halfY))
            and not(player.isColliding(nextX - halfX, player.y + halfY - 1)) then
            -- no collision
            player.x = nextX;
        else
            -- collision, move to nearest tile
            player.x = nextX + tileMap.TileWidth - ((nextX - halfX) % tileMap.TileWidth);
        end
    end

	-- check all slope collider and responce.
	checkForSlopes();
end

-- returns true if the coordinates given intersect a map tile
function player.isColliding(x, y)
    -- get tile coordinates
    local tileX, tileY = math.floor(x / tileMap.TileWidth), math.floor(y / tileMap.TileHeight);
    
    -- grab the tile at given point
    if tileMap.map[tileY][tileX] == 1 then
		return true;
	end
    
    -- return true if the point overlaps a solid tile
    return false;
end

function player.draw()
	-- round our x, y values
    local x, y = math.floor(player.x), math.floor(player.y)

	-- draw the player
	love.graphics.setColor(255, 0, 0, 200);
    love.graphics.rectangle("fill", x - player.width / 2, y - player.height / 2, player.width, player.height);
    love.graphics.setColor(255, 255, 255);
end
--
--Function love engine
-- =====================================================================

function love.load()
	io.stdout:setvbuf("no");
	--
	tileMap = {};
	tileMap.map = {
		{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
		{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{1, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{1, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 1, 1, 1, 3, 0, 0, 0, 0, 0, 0, 0, 1},
		{1, 0, 0, 0, 0, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3, 0, 0, 0, 0, 0, 0, 1},
		{1, 0, 0, 0, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 0, 0, 0, 0, 0, 1},
		{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
	};
	tileMap.TileWidth = 32;
	tileMap.TileHeight = 32;

	-- initialize player.
	player.load();

	hasJumped = false;
end

function love.update(dt)
	-- check controls
    if love.keyboard.isDown("right") then
        player.moveRight();
    end
    if love.keyboard.isDown("left") then
        player.moveLeft();
    end
    if (love.keyboard.isDown("x") or love.keyboard.isDown("up")) and not(hasJumped) then
        hasJumped = true;
        player.jump();
    end

	player.update(dt);
end

function love.keyreleased(key)
	if key == "escape" then
        love.event.push("quit")   -- actually causes the app to quit
    end
    if (key == "right") or (key == "left") then
        player.stop()
    end
    if (key == "x" or key == "up") then
        hasJumped = false
    end
end

function love.draw()
	-- draw tile map.
	drawTileMap();

	-- draw player.
	player.draw();
end

-- draw tile map.
function drawTileMap()
	for y = 1, #tileMap.map do
		for x = 1, #tileMap.map[1] do
			love.graphics.setColor(0, 0, 255); -- blue color
			--
			if tileMap.map[y][x] == 1 then
				love.graphics.rectangle("fill", x * tileMap.TileWidth, y * tileMap.TileHeight, tileMap.TileWidth, tileMap.TileHeight);
			end
			--
			love.graphics.setColor(255, 255, 255);

			love.graphics.setColor(0, 255, 0); -- green color
			--
			-- left slope.
			if tileMap.map[y][x] == 2 then
				drawslopeLeft(x * 32, (y * 32) + 32, (x * 32) + 32, (y * 32));
			end

			-- right slope.
			if tileMap.map[y][x] == 3 then
				drawslopeRight(x * 32, (y * 32), (x * 32) + 32, (y * 32) + 32);
			end
			love.graphics.setColor(255, 255, 255);
		end
	end
end
User avatar
Foxcraft
Prole
Posts: 49
Joined: Sat Mar 22, 2014 8:56 pm

Re: help slope platformer 2d

Post by Foxcraft »

Hello luislasonbra,

I think that when you are trying to go down either slope, being on the ground (player.onFloor == true) is not allowing the square to slide down. It goes horizontal like it would on normal flat ground.

While on a slope, you need to be able to go down further despite being on the ground. I think that's what needs to be figured out.

I hope that helps. :)
Post Reply

Who is online

Users browsing this forum: No registered users and 63 guests