Page 1 of 1

Player Movement - Pythagorean formula - 8 directions

Posted: Fri Dec 11, 2015 9:47 pm
by TheGuardian163
I was following a space invaders tutorial on youtube (just started learning Lua) and deciding to play around instead of following it

You can move in 8 different directions using the arrow keys, you can sprint using the Z key and shoot using the X key (only upwards)

I used pythagorean formula to get the right speed when going on a 'combined' direction (the diagonal of a square is longer than it's height, so doing "player.y = player.speed / 2" and "player.x = player.speed / 2" made the player move faster than it should

I'd like to learn about structuring my code better - how could I make it cleaner?

Here's the code:
http://pastebin.com/VDSHsbSL

Re: Player Movement - Pythagorean formula - 8 directions

Posted: Fri Dec 11, 2015 11:03 pm
by airstruck
I'd get the x input and y input as values in (-1, 0, 1), create a unit vector from that, and scale it by the desired speed. Something like this maybe:

Code: Select all

-- this normalizes and then scales a vector
local function setVectorLength (vx, vy, length)
    local currentLength = math.sqrt(vx * vx + vy * vy)
    return vx / currentLength * length, vy / currentLength * length
end

local function getInputX ()
    local value = 0
    if love.keyboard.isDown("left") then
        value = value - 1
    end
    if love.keyboard.isDown("right") then
        value = value + 1
    end
    return value
end

local function getInputY ()
    local value = 0
    if love.keyboard.isDown("up") then
        value = value - 1
    end
    if love.keyboard.isDown("down") then
        value = value + 1
    end
    return value
end

-- inside update...

local speed = love.keyboard.isDown("z") and player.fastSpeed or player.slowSpeed
local vx, vy = setVectorLength(getInputX(), getInputY(), speed)

player.x = player.x + vx -- * dt
player.y = player.y + vy -- * dt

Re: Player Movement - Pythagorean formula - 8 directions

Posted: Sat Dec 12, 2015 1:28 pm
by Ortimh
For the sake of simplifying everything I'd use square root of 2.
For me this is the code that looks clean:

Code: Select all

local sqrt2 = math.sqrt(2)

function love.load()
	player = {
		x = 0,
		y = 525,
		bullets = {},
		cooldown = 0,
		speed = {
			normal = 120,
			fast = 240
		},
		fire = function()
			if (player.cooldown <= 0) then
				player.cooldown = 45
				
				table.insert(player.bullets, {
					x = player.x + 30,
					y = player.y - 30
				})
			end
		end
	}
end

function love.update(dt)
	player.cooldown = player.cooldown < 0 and 0 or player.cooldown - 120 * dt
	
	local speed = love.keyboard.isDown("z") and player.speed.fast or player.speed.normal
	local velocityX = love.keyboard.isDown("left") and -speed or (love.keyboard.isDown("right") and speed or 0)
	local velocityY = love.keyboard.isDown("up") and -speed or (love.keyboard.isDown("down") and speed or 0)
	local diagonal = velocityX ~= 0 and velocityY ~= 0
	
	player.x = player.x + (diagonal and velocityX / sqrt2 or velocityX) * dt
	player.y = player.y + (diagonal and velocityY / sqrt2 or velocityY) * dt
	
	if (love.keyboard.isDown("x")) then
		player.fire()
	end
	
	for index, bullet in ipairs(player.bullets) do
		if (bullet.y < -10) then
			table.remove(player.bullets, index)
		else
			bullet.y = bullet.y - 720 * dt
		end
	end
end

function love.draw()
	love.graphics.setColor(140, 0, 140)
	love.graphics.rectangle("fill", player.x, player.y, 60, 40)
	love.graphics.setColor(255, 255, 125)
	
	for index, bullet in ipairs(player.bullets) do
		love.graphics.rectangle("fill", bullet.x, bullet.y, 2, 30)
	end
end

Re: Player Movement - Pythagorean formula - 8 directions

Posted: Sat Jun 22, 2024 2:24 pm
by Lovingsoul1337

Code: Select all

--player

local gameObject = require('gameObjects/gameObject')
local player = gameObject:new()

--player sprite

player.image = love.graphics.newImage('assets/testRectangle.png')

--class vars

player.x = 0
player.y = 0
player.speed = 0
player.acceleration = 15
player.deceleration = 7
player.maxSpeed = 25
player.velocityX = 0
player.velocityY = 0

--enums

player.directions = {
    UP = 'UP',
    DOWN = 'DOWN',
    LEFT = 'LEFT',
    RIGHT = 'RIGHT',
    RIGHTUP = 'RIGHTUP',
    RIGHTDOWN = 'RIGHTDOWN',
    LEFTUP = 'LEFTUP',
    LEFTDOWN = 'LEFTDOWN',
    NONE = 'NONE'
}

player.direction = player.directions.NONE

player.states = {
    IDLE = 'IDLE'
}

player.state = player.states.IDLE

function player:new()
    local obj = {}
    setmetatable(obj, self)
    self.__index = self
    return obj
end
 
function player:applyVelocity(dt)

    if self.direction == self.directions.UP then
        self.velocityY = self.velocityY - self.acceleration * dt
    end

    if self.direction == self.directions.LEFT then
        self.velocityX = self.velocityX - self.acceleration * dt
    end

    if self.direction == self.directions.DOWN then
        self.velocityY = self.velocityY + self.acceleration * dt
    end

    if self.direction == self.directions.RIGHT then
        self.velocityX = self.velocityX + self.acceleration * dt
    end

    if self.direction == self.directions.RIGHTUP then
        self.velocityX = self.velocityX + self.acceleration * dt
        self.velocityY = self.velocityY - self.acceleration * dt
    end

    if self.direction == self.directions.LEFTUP then
        self.velocityX = self.velocityX - self.acceleration * dt
        self.velocityY = self.velocityY - self.acceleration * dt
    end

    if self.direction == self.directions.RIGHTDOWN then
        self.velocityX = self.velocityX + self.acceleration * dt
        self.velocityY = self.velocityY + self.acceleration * dt
    end

    if self.direction == self.directions.LEFTDOWN then
        self.velocityX = self.velocityX - self.acceleration * dt
        self.velocityY = self.velocityY + self.acceleration * dt
    end

    self:normalizeVector()

end

function player:applyDeceleration(dt)
    self.velocityX = self.velocityX * (1 - self.deceleration * dt)
    self.velocityY = self.velocityY * (1 - self.deceleration * dt)
end

function player:setPosition()
    self.x = self.x + self.velocityX
    self.y = self.y + self.velocityY   
end 

function player:checkForInput(dt)

    self.direction = self.directions.NONE

    if love.keyboard.isDown('w') then
        self.direction = self.directions.UP
    end

    if love.keyboard.isDown('a') then
        self.direction = self.directions.LEFT
    end

    if love.keyboard.isDown('s') then
        self.direction = self.directions.DOWN
    end

    if love.keyboard.isDown('d') then
        self.direction = self.directions.RIGHT
    end

    if love.keyboard.isDown('w') and love.keyboard.isDown('d') then
        self.direction = self.directions.RIGHTUP
    end

    if love.keyboard.isDown('w') and love.keyboard.isDown('a') then
        self.direction = self.directions.LEFTUP
    end

    if love.keyboard.isDown('s') and love.keyboard.isDown('d') then
        self.direction = self.directions.RIGHTDOWN
    end

    if love.keyboard.isDown('s') and love.keyboard.isDown('a') then
        self.direction = self.directions.LEFTDOWN
    end

    if love.keyboard.isDown('return') then
        print(self.direction)
    end

end

function player:normalizeVector()
    local length = math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY)
    if length > self.maxSpeed then
        self.velocityX = (self.velocityX / length) * self.maxSpeed
        self.velocityY = (self.velocityY / length) * self.maxSpeed
    end
end

function player:update(dt)
    self:checkForInput()
    self:applyVelocity(dt)
    self:setPosition()
    self:applyDeceleration(dt)
end

function player:draw()
    love.graphics.draw(self.image, self.x, self.y)
    love.graphics.print(self.velocityX, 0, 0)
    love.graphics.print(self.velocityY, 0, 10)
end

function player:sayHi()
end

return player
i have it like this.

Re: Player Movement - Pythagorean formula - 8 directions

Posted: Sat Jun 22, 2024 10:28 pm
by dusoft
TheGuardian163 wrote: Fri Dec 11, 2015 9:47 pm I was following a space invaders tutorial on youtube (just started learning Lua) and deciding to play around instead of following it

You can move in 8 different directions using the arrow keys, you can sprint using the Z key and shoot using the X key (only upwards)

I used pythagorean formula to get the right speed when going on a 'combined' direction (the diagonal of a square is longer than it's height, so doing "player.y = player.speed / 2" and "player.x = player.speed / 2" made the player move faster than it should

I'd like to learn about structuring my code better - how could I make it cleaner?

Here's the code:
http://pastebin.com/VDSHsbSL
Also, please use Support forum for requests/questions like this instead of Libraries and Tools. This forum is strictly for reusable / open source libs or useful tools.