Calling (importing) other .lua files outside main.lua in Love2D - love2d

So, I wanted to clean up my code by splitting it into seperate files. But for some reason I can't call the script I want to call through my main.lua.
Here's my main.lua script:
function love.load()
require "splash.lua"
splash.load()
end
function love.update(dt)
splash.update(dt)
end
function love.draw() print("Draw")
splash.draw()
love.graphics.print("FPS "..tostring(love.timer.getFPS( )), 5, 5) print("fps")
love.graphics.setColor(255,0,0) --Red
love.graphics.rectangle("fill", 3, 3, 60, 20)
end
And here's my splash.lua script, separate from the main.lua file:
function splash.load()
timer = 0 print("fadein")
alpha = 0
fadein = 2
display = 4
fadeout = 6
splashScreen = love.graphics.newImage("/images/Splash1.png")
end
function splash.update(dt)
timer = timer + dt
if 0 < timer and timer < fadein then
alpha = timer / fadein
end
if fadein < timer and timer < display then
alpha = 1
end
if display < timer and timer < fadeout then
alpha = 1 - ((timer - display) / (fadeout - display))
end
end
function splash.draw()
love.graphics.setColor(1, 1, 1, alpha)
local sx = love.graphics.getWidth() / splashScreen:getWidth()
local sy = love.graphics.getHeight() / splashScreen:getHeight()
love.graphics.draw(splashScreen, 0, 0, 0, sx, sy)
end
I've searched everywhere on this topic, and the other answers are either extremely vague or outdated. All I want to do is to make the splash.lua run when I start Love.

There were two problems which I noticed and once I fixed them something ran.
Problem 1
In main.lua, require "splash.lua" should be require "splash". If you code in other languages like python, java or javascript, you can think of require as similar to import.
Problem 2
In splash.lua, you are referencing an object(splash) which doesn't exist. To keep your code as similar as I could, I inserted the line splash = {} at the top of splash.lua. Once the object splash is created, you are then able to create functions for this object(splash.load(), splash.update(), and splash.draw()). This isn't a problem in main.lua because love is an object which already exists when the love2d game engine starts.
main.lua
function love.load()
require "splash"
splash.load()
end
function love.update(dt)
splash.update(dt)
end
function love.draw() print("Draw")
splash.draw()
love.graphics.print("FPS "..tostring(love.timer.getFPS( )), 5, 5) print("fps")
love.graphics.setColor(255,0,0) --Red
love.graphics.rectangle("fill", 3, 3, 60, 20)
end
splash.lua
splash = {}
function splash.load()
timer = 0 print("fadein")
alpha = 0
fadein = 2
display = 4
fadeout = 6
splashScreen = love.graphics.newImage("/images/Splash1.png")
end
function splash.update(dt)
timer = timer + dt
if 0 < timer and timer < fadein then
alpha = timer / fadein
end
if fadein < timer and timer < display then
alpha = 1
end
if display < timer and timer < fadeout then
alpha = 1 - ((timer - display) / (fadeout - display))
end
end
function splash.draw()
love.graphics.setColor(1, 1, 1, alpha)
local sx = love.graphics.getWidth() / splashScreen:getWidth()
local sy = love.graphics.getHeight() / splashScreen:getHeight()
love.graphics.draw(splashScreen, 0, 0, 0, sx, sy)
end
Side note: from reading your code, I'm not sure if you understand entirely how the load, update, and draw functions work. Love is an object created by the love2d game engine. The engine runs the load function only once when the game starts. The update function then continually checks for changes to the world that the game exists in and applies the code within love.update according to the conditions inside it. The draw function continually draws what it is told over and over again. These things happen automatically because it's already programmed into the love2d game engine.
The only reason I think you might be confused in this area is that you created a separate splash.load, splash.update, and splash.draw. You can technically name whatever functions you're calling anything you want, I just had the feeling that you might think that these load, update and draw functions might be called automatically, which they're not. Love2d only calls the load, update, and draw functions automatically for the love object.

Changing your require command to the following should work:
require("splash")
Additionally you should create the splash table before creating functions for said table.
splash = {}
splash.myFunction()
.
.
.

Related

I am trying to set all rigidbodys' velocity to 0, then to what it was before

So I have been trying to create a pause menu for the past few hours. However, I cannot figure out how to stop the rigidbodies from moving. If there is a way to stop all rigidbodies at once, please tell me, if not, I can set it to each and every script with a rigid body. Here is my code so far:
extends Position3D
onready var charCamera = get_viewport().get_camera()
##var direction = Camera.global_transform.basis.get_euler()
signal spawned(spawn)
export(PackedScene) var spawnling_scene
var linear_velocity_on_pause = 0
var not_paused_anymore = false
var paused = false
#var Popup1 = self.get_parent().get_parent().get_parent().get_node("Popup")
func _physics_process(_delta):
if self.get_parent().get_parent().get_parent().get_node("Popup").visible == false:
if Input.is_action_pressed("leftClick"):
spawn()
if paused == true:
not_paused_anymore = true
paused = false
if self.get_parent().get_parent().get_parent().get_node("Popup").visible == true:
linear_velocity_on_pause = spawnling_scene.instance().linear_velocity
paused = true
spawnling_scene.instance().set_mode(1)
spawnling_scene.instance().linear_velocity = get_parent().get_parent().get_parent().get_node("LinearVelocityOf0").linear_velocity
if not_paused_anymore == true:
spawnling_scene.instance().set_mode(0)
spawnling_scene.instance().linear_velocity = linear_velocity_on_pause
not_paused_anymore = false
func spawn():
var spawnling = spawnling_scene.instance()
spawnling.linear_velocity = charCamera.global_transform.basis.z * -100
#spawnling.global_transform.basis = charCamera.global_transform.basis
add_child(spawnling)
spawnling.set_as_toplevel(true)
emit_signal("spawned", spawnling)
##insert pause system
return spawnling
##var spawnling = spawnling_scene.instance()
##
## add_child(spawnling)
## spawnling.set_as_toplevel(true)
I'm not answering the question of how to set the velocity of all rigid bodies to zero.
If you want to make a pause menu, this is what you should know:
Godot has a puse system, which you can use like this to pause:
get_tree().paused = true
And to resume:
get_tree().paused = false
See Pausing Games.
Which Nodes gets to execute when get_tree().paused is set to true depend on their pause_mode property. By default they will all stop, but if you set their pause_mode to PAUSE_MODE_PROCESS they will continue to work when get_tree().paused is set to true. And that is what you want to do with the Node that make up your pause menu UI.
However, that system will not pause shaders. Their TIME will continue to tick. If you want to "freeze" shaders you can set a 0 to their time scaling like this:
VisualServer.set_shader_time_scale(0)
Set it to 1 for normal speed:
VisualServer.set_shader_time_scale(0)
And you can set other values to have them slow down or speed up.
Speaking of slow down and speed up. If you want to do that for the rest of the game (not just shaders), you can use Engine.time_scale. And if there is some timing that you don't want to be affected, you would have to write it using the time functions in the OS class.

How would I rotate a character based on their camera? (Roblox)

In Roblox, your camera has a CFrame with a lookVector and so on. What I'm trying to accomplish is to detect when a player has pressed their right mouse button, and through a loop, rotate their character based on the CFrame of the camera until the button is released.
I've pretty much got it, but instead of rotating the character model, it turns the screen black and kills the player. I've seen this done in RPGs on Roblox before, so I know it's possible, and probably fairly easy. I've worked with CFrames quite a bit in the past, so I'm not sure why I'm having such a hard time with this.
After a couple hours of playing around with ideas and checking online, I thought I'd just ask the question to save time. What's the correct way to achieve this?
Edit: My bad, this is what I have so far. I fixed the black screen, but the player still just dies.
local UIS,Player,Camera,Character,MB2Down = game:GetService('UserInputService'),game.Players.LocalPlayer,workspace.Camera,script.Parent,false
local Torso = Character:FindFirstChild('Torso') or Character:FindFirstChild('UpperTorso')
UIS.InputEnded:Connect(function(Input)
if Input.UserInputType == Enum.UserInputType.MouseButton2 and MB2Down then
MB2Down = false
Character.Humanoid.AutoRotate = true
end
end)
UIS.InputBegan:connect(function(Input,onGui)
if Input.UserInputType == Enum.UserInputType.MouseButton2 and not onGui then
MB2Down = true
Character.Humanoid.AutoRotate = false
while MB2Down and wait() do
Torso.CFrame = CFrame.new(Vector3.new(Torso.CFrame),Vector3.new(Camera.CFrame.p))
end
end
end)
You've almost got it, but let me take a slightly different approach to my solution. When the player presses the right mouse button, let's connect a function to the Heartbeat event that will update the character's rotation to the camera's. Also, we will rotate the HumanoidRootPart instead of the Torso/UpperTorso. The HumanoidRootPart is the PrimaryPart of the character model, and thus is the part we should manipulate if we want to manipulate the model as a whole.
The way we will lock the player's rotation to the camera is as follows:
Get the position of the character.
Get the rotation of the camera (by using arc-tangent and camera's look-vector).
Construct the new CFrame for the player using the position and rotation from steps 1 and 2.
Apply the CFrame to the character's HumanoidRootPart.
The following code is in a LocalScript and is placed under StarterCharacterScripts:
local userInput = game:GetService("UserInputService")
local player = game.Players.LocalPlayer
local character = script.Parent
local root = character:WaitForChild("HumanoidRootPart")
local humanoid = character:WaitForChild("Humanoid")
local camera = workspace.CurrentCamera
local dead = false
local heartbeat = nil
function LockToCamera()
local pos = root.Position
local camLv = camera.CFrame.lookVector
local camRotation = math.atan2(-camLv.X, -camLv.Z)
root.CFrame = CFrame.new(root.Position) * CFrame.Angles(0, camRotation, 0)
end
userInput.InputEnded:Connect(function(input)
if (input.UserInputType == Enum.UserInputType.MouseButton2 and heartbeat) then
heartbeat:Disconnect()
heartbeat = nil
humanoid.AutoRotate = true
end
end)
userInput.InputBegan:Connect(function(input, processed)
if (processed or dead) then return end
if (input.UserInputType == Enum.UserInputType.MouseButton2) then
humanoid.AutoRotate = false
heartbeat = game:GetService("RunService").Heartbeat:Connect(LockToCamera)
end
end)
humanoid.Died:Connect(function()
dead = true
if (heartbeat) then
heartbeat:Disconnect()
heartbeat = nil
end
end)
Let me know if you need any clarification.

macOS Sierra: Emulate Mouse Down and Up

after an update to Sierra I had to find that Karabiner is not working anymore, which could emulate pointer clicks really well.
Any chance to get that via Swift or Apple Script or Obj.C ?
Background: Using Karabiner(and seil) I could bind caps-lock + d down and up to mouse down and up and in between the trackpad movement was understood. My trackpad is not processing keypress anymore but works still fine for pointer moves.
Answering myself, hacked it in hammerspoon. Was quite tricky to get chrome select working, maybe it saves somebody an hour or two:
1 ~/.hammerspoon $ cat init.lua
--[[ Left Keyboard Mouse (alt-d)
The main problem was to get chrome based apps select text when we drag via
keyboard.
You MUST return true always in the handle_drag otherwise it fails to select.
FF works, terminal works, chrome apps (atom, ...) don't.
But true is preventing further processing of the drag coords,
hs.mouse.getAbsolutePosition remains constant while dragging (!)
=> i.e. we MUST calc them via DeltaX, DeltaY, see below.
--]]
hs.alert.show("Config loaded")
-- all mechanics stolen from here:
-- local vimouse = require('vimouse')
-- vimouse('cmd', 'm')
now = hs.timer.secondsSinceEpoch
evt = hs.eventtap
evte = evt.event
evtypes = evte.types
evp=evte.properties
drag_last = now(); drag_intv = 0.01 -- we only synth drags from time to time
mp = {['x']=0, ['y']=0} -- mouse point. coords and last posted event
l = hs.logger.new('keybmouse', 'debug')
dmp = hs.inspect
-- The event tap. Started with the keyboard click:
handled = {evtypes.mouseMoved, evtypes.keyUp }
handle_drag = evt.new(handled, function(e)
if e:getType() == evtypes.keyUp then
handle_drag:stop()
post_evt(2)
return nil -- otherwise the up seems not processed by the OS
end
mp['x'] = mp['x'] + e:getProperty(evp.mouseEventDeltaX)
mp['y'] = mp['y'] + e:getProperty(evp.mouseEventDeltaY)
-- giving the key up a chance:
if now() - drag_last > drag_intv then
-- l.d('pos', mp.x, 'dx', dx)
post_evt(6) -- that sometimes makes dx negative in the log above
drag_last = now()
end
return true -- important
end)
function post_evt(mode)
-- 1: down, 2: up, 6: drag
if mode == 1 or mode == 2 then
local p = hs.mouse.getAbsolutePosition()
mp['x'] = p.x
mp['y'] = p.y
end
local e = evte.newMouseEvent(mode, mp)
if mode == 6 then cs = 0 else cs=1 end
e:setProperty(evte.properties.mouseEventClickState, cs)
e:post()
end
hs.hotkey.bind({"alt"}, "d",
function(event)
post_evt(1)
handle_drag:start()
end
)
and alt I mapped to capslock via karabiner elements.

how does scrapy-splash handle infinite scrolling?

I want to reverse engineering the contents generated by scrolling down in the webpage. The problem is in the url https://www.crowdfunder.com/user/following_page/80159?user_id=80159&limit=0&per_page=20&screwrand=933. screwrand doesn't seem to follow any pattern, so the reversing the urls don't work. I'm considering the automatic rendering using Splash. How to use Splash to scroll like browsers? Thanks a lot!
Here are the codes for two request:
request1 = scrapy_splash.SplashRequest(
'https://www.crowdfunder.com/user/following/{}'.format(user_id),
self.parse_follow_relationship,
args={'wait':2},
meta={'user_id':user_id, 'action':'following'},
endpoint='http://192.168.99.100:8050/render.html')
yield request1
request2 = scrapy_splash.SplashRequest(
'https://www.crowdfunder.com/user/following_user/80159?user_id=80159&limit=0&per_page=20&screwrand=76',
self.parse_tmp,
meta={'user_id':user_id, 'action':'following'},
endpoint='http://192.168.99.100:8050/render.html')
yield request2
ajax request shown in browser console
To scroll a page you can write a custom rendering script (see http://splash.readthedocs.io/en/stable/scripting-tutorial.html), something like this:
function main(splash)
local num_scrolls = 10
local scroll_delay = 1.0
local scroll_to = splash:jsfunc("window.scrollTo")
local get_body_height = splash:jsfunc(
"function() {return document.body.scrollHeight;}"
)
assert(splash:go(splash.args.url))
splash:wait(splash.args.wait)
for _ = 1, num_scrolls do
scroll_to(0, get_body_height())
splash:wait(scroll_delay)
end
return splash:html()
end
To render this script use 'execute' endpoint instead of render.html endpoint:
script = """<Lua script> """
scrapy_splash.SplashRequest(url, self.parse,
endpoint='execute',
args={'wait':2, 'lua_source': script}, ...)
Thanks Mikhail, I tried your scroll script, and it worked, but I also notice that your script scroll too much one time, some js have no time too render and is skipped, so I do some little change as follow:
function main(splash)
local num_scrolls = 10
local scroll_delay = 1
local scroll_to = splash:jsfunc("window.scrollTo")
local get_body_height = splash:jsfunc(
"function() {return document.body.scrollHeight;}"
)
assert(splash:go(splash.args.url))
splash:wait(splash.args.wait)
for _ = 1, num_scrolls do
local height = get_body_height()
for i = 1, 10 do
scroll_to(0, height * i/10)
splash:wait(scroll_delay/10)
end
end
return splash:html()
end
I do not think that setting the number of scrolls hard coded is a good idea for infinite scroll pages, so I modified the above-mentioned code like this:
function main(splash, args)
current_scroll = 0
scroll_to = splash:jsfunc("window.scrollTo")
get_body_height = splash:jsfunc(
"function() {return document.body.scrollHeight;}"
)
assert(splash:go(splash.args.url))
splash:wait(3)
height = get_body_height()
while current_scroll < height do
scroll_to(0, get_body_height())
splash:wait(5)
current_scroll = height
height = get_body_height()
end
splash:set_viewport_full()
return splash:html()
end

Matlab instance variable not being saved, reverts to 0s

I am struggling to understand why my instance variables not being saved. Whenever I make a change to CurrentSettings, it does not appear next time I call another function. Basically it does not save and reverts to 0s after each function.
classdef laserControl
%LASERCONTROL This module is designed to control the laser unit.
% It can set the filter position, open and close the shutter and turn
% on/off the laser.
%
%%%%%%%%%%PORT LISTINGS%%%%%%%%%%%
%The set filter command is on port0
%The set shutter is in port1
%Laser 1 on port2
%Laser 2 on port3
%The filter digits are on ports 8-15 (the are on the second box)
properties%(GetAccess = 'public', SetAccess = 'private')
laserPorts; %The #'s of the output ports
currentSettings; %Current high/low settings
dio;
end
methods
%Constructor
%Opens the connection with the digital outputs
%Make sure to close the connection when finished
function Lobj = laserControl()
%Setup the laser
Lobj.laserPorts = [0:3 8:15];% 8:15
Lobj.currentSettings = zeros(1, length(Lobj.laserPorts));
%Make connection and reset values
Lobj.dio = digitalio('nidaq','Dev1');
addline(Lobj.dio, Lobj.laserPorts, 'out');
putvalue(Lobj.dio, Lobj.currentSettings);
end
%Closes the connection to the digital output
function obj = CloseConnection(obj)
putvalue(obj.dio, zeros(1, length(obj.currentSettings)));
delete(obj.dio);
clear obj.dio;
end
%Sets the position of the filter.
%positionValue - the integer amount for the position, cannot be
%larger than 150, as regulated by the box.
%The set filter command is on port0
%The filter digits are on ports 8-15 (the are on the second box)
function obj = SetFilterPosition(obj, positionValue)
if 0 <= positionValue && positionValue < 150
binaryDigit = de2bi(positionValue); %Convert it to binary form
%LaserOn OldSettings NewValue ExtraZeros
obj()
obj.currentSettings()
obj.currentSettings = [1 obj.currentSettings(1, 2:4) binaryDigit...
zeros(1, 8 - length(binaryDigit))];
putvalue(obj.dio, obj.currentSettings);
else
display('Error setting the filer: Value invalid');
end
end
end
Because your class does not inherit from handle, you've written a "value"-type class - in other words, when you make changes, you must capture the return value, like so:
myObj = SetFilterPosition( myObj, 7 );
For more on handle and value classes, see the doc