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.
Related
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.
I made this code thinking it would allow the player to jump Twice and the second Jump be the power of its leader stat but Instead it doesn't even allow the player to Jump a second time.
local UIS = game:GetService("UserInputService")
local player = game.Players.LocalPlayer
local character
local humanoid
local canDoubleJump = false
local hasDoubleJumped = false
local oldPower
local time_delay = 0.2
local jump_multiplier = player.leaderstats.JumpBoost.Value
function onJumpRequest()
if not character or not humanoid or not
character:IsDescendantOf(workspace) or humanoid:GetState() ==
Enum.HumanoidStateType.Dead then
return
end
if canDoubleJump and not hasDoubleJumped then
hasDoubleJumped = true
humanoid.JumpPower = oldPower * jump_multiplier
humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
end
end
local function characterAdded(new)
character = new
humanoid = new:WaitForChild("Humanoid")
hasDoubleJumped = false
canDoubleJump = false
oldPower = humanoid.JumpPower
humanoid.StateChanged:connect(function(old, new)
if new == Enum.HumanoidStateType.Landed then
canDoubleJump = false
hasDoubleJumped = false
humanoid.JumpPower = oldPower
elseif new == Enum.HumanoidStateType.Freefall then
wait(time_delay)
canDoubleJump = true
end
end)
end
if player.Character then
characterAdded(player.Character)
end
player.CharacterAdded:connect(characterAdded)
UIS.JumpRequest:connect(onJumpRequest)
I expected the player to Jump Twice with the second Jump having the power of the leader stat(I only put that and this because it says it wants more detail)
LocalScripts do not execute in game.Workspace: they only run on clients, hence the term 'local'; Scripts, on the other hand, are server-side.
You could use a Script to place your double-jump script--a LocalScript--into incoming players' character models.
-- Server-side Script
local players = game:GetService("Players")
local jumpScript = script:WaitForChild("JumpScript") -- Assume the double-jump script is a LocalScript called 'JumpScript'.
players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function(char)
-- Check to make sure the character model does not already contain the double-jump script, just in case.
local clone = char:FindFirstChild("JumpScript")
if (not clone) then
clone = jumpScript:Clone()
clone.Parent = char
end
end)
end)
As a note, it is good practice to put server-side scripts like this into ServerScriptStorage instead of workspace or Lighting. (You can read about the safety of ServerScriptStoragehere.)
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.
I'm fairly new to psychopy but I'm having a lot of trouble recording keyboard events so far. The keyboard demo works so I know it is possible, but when I implement the code in my own program it doesn't record any keyboard activity at all. Right now my program is super simple as I'm just trying to get the hang of it. I have a picture and want to record the duration of keypresses during the time the picture is on screen. I have a couple print statements as sanity checks and when I run it (and am using the keyboard) it doesn't print anything. Here's an outline of my code:
from psychopy.iohub import launchHubServer, EventConstants
io = launchHubServer()
keyboard = io.devices.keyboard
keyboard.reporting = True
#-------Start Routine "trial"-------
continueRoutine = True
io.clearEvents('all')
duration_lst=[]
while continueRoutine and routineTimer.getTime() > 0:
# get current time
t = trialClock.getTime()
frameN = frameN + 1 # number of completed frames (so 0 is the first frame)
# update/draw components on each frame
# *image* updates
if t >= 0.0 and image.status == NOT_STARTED:
# keep track of start time/frame for later
image.tStart = t # underestimates by a little under one frame
image.frameNStart = frameN # exact frame index
image.setAutoDraw(True)
if image.status == STARTED and t >= (0.0 + (5.0- win.monitorFramePeriod*0.75)): #most of one frame period left
image.setAutoDraw(False)
# *ISI* period
if t >= 0.0 and ISI.status == NOT_STARTED:
# keep track of start time/frame for later
ISI.tStart = t # underestimates by a little under one frame
ISI.frameNStart = frameN # exact frame index
ISI.start(0.5)
elif ISI.status == STARTED: #one frame should pass before updating params and completing
ISI.complete() #finish the static period
# get keyboard events
for event in keyboard.getEvents():
print event
if event.type == EventConstants.KEYBOARD_CHAR:
key_press_duration=event.duration
duration_lst.append(key_press_duration)
print duration_lst
# check if all components have finished
if not continueRoutine: # a component has requested a forced-end of Routine
break
continueRoutine = False # will revert to True if at least one component still running
for thisComponent in trialComponents:
if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
continueRoutine = True
break # at least one component has not yet finished
# check for quit (the Esc key)
if endExpNow or event.getKeys(keyList=["escape"]):
core.quit()
# refresh the screen
if continueRoutine: # don't flip if this routine is over or we'll get a blank screen
win.flip()
I tried stripping off all unnecessary stuff here (variables, window, stimuli etc.) and uses keyboard.getReleases() so it boils down to this:
from psychopy import iohub
io = iohub.launchHubServer()
keyboard = io.devices.keyboard
print 'press something now!'
while True:
# get keyboard releases
for event in keyboard.getReleases():
print 'Released!'
This should print all info about each key release in the console. It works for me, at least. If it also works for you, the problem is probably related to something else in your script.
function saveScore()
local path = system.pathForFile("scoredata001.txt", system.DocumentsDirectory)
local file = io.open(path, "w")
if file then
local score=get_score() --The get_score() returns the value of current score which is saved in 'score'.
local newScore = compareScore()
local contents = tostring( newScore )
file:write( contents )
io.close( file )
return true
else
print("Error: could not write Score")
return false
end
end
function loadScore()
local path = system.pathForFile("scoredata001.txt", system.DocumentsDirectory)
local contents = ""
local file = io.open( path, "r" )
if file then
local contents = file:read( "*a" )
local score = tonumber(contents);
io.close( file )
return score
end
print("Could not read scores from scoredata.txt")
return nil
end
function return_highScore()
local highscore=loadScore()
if highscore==nil then
highscore=0
end
return highscore
end
function compareScore()
local highscore=return_highScore()
if highscore then
local currscore=get_score()
if highscore==0 then
return highscore
elseif currscore>highscore then
return currscore
end
end
return true
end
function disp_permScore()
local display_score=return_highScore()
text_display2= display.newText("GAME OVER!\n BEST: " ..display_score, 0, 0, "Helvetica", 80)
text_display2.x = centerX
text_display2.y = centerY
text_display2.alpha=1
function gameOver()
mainScreen()
saveScore()
disp_permScore()
end
(This is with refernce to previous question Permission issues in lua )
Basically I'm trying to build a game in lua (This is my first ever game)
But, I'm unable to save highscore to file. If it gets saved, then I'm unable to retrieve them. (In short, I always some or the other error/problem in executing the code.
Please have a look at the code above. I want to display both high score and current score. Current score is being displayed perfect. This is something I tried yesterday night. But now, the high score is not being saved in file. (i.e. the best always displays 0) Also, the cmd says "unable to read scores form scoredata.txt) I'm unable to find where I went wrong.
Please help with this?
Please tell where do I go wrong?
Also, if possible, provide (or edit) the correct code please?
There seems to be a problem on this line
if highscore==0
then
return highscore
Meaning you check if the highscore is 0 and if it is then you return it instead of the actual higher score.
Also, I don't know if your code was just pasting error, but without indenting your code it becomes really hard to read. Try and look again I indentet it and now the error becomes really easy to spot.