DaveTheCoder Made no difference. Thanks for the tip though!
Do you know any way I can still access and change these variables from the subroutine?
DaveTheCoder Made no difference. Thanks for the tip though!
Do you know any way I can still access and change these variables from the subroutine?
Here it is in text format.
var latestX : float = 0.0
var latestY : float = 0.0
var GetNextShake = func():
while true:
var X = randf_range(min, max) * [-1, 1].pick_random()
var Y = randf_range(min, max) * [-1, 1].pick_random()
if X != latestX and Y != latestY:
latestX = X
latestY = Y
print(latestX, ", ", latestY)
break
var SingleShake = func():
print("New tween", ", pos = ", latestX, ", ", latestY)
GetNextShake.call()
#Tween camera position to new coordinate
await physics.tween({"object" : camera, "property" : "position", "final" : originalCameraPos + Vector3(latestX, latestY, 0), "time" : 1.0 / speed})
if index: #Make sure index exists
if data["mode"] is int: #This means shake has a time limit on it (Should end after x seconds)
pass
elif data["mode"] is bool: #This means shake is on toggle mode (Most likely a suttle and long shake like elevator scene)
if data["mode"] == true: #Starting a shake
print("true loop")
while index["mode"] == true:
await SingleShake.call()
camera.position = originalCameraPos
Min and max change with the function but here in this case Min = 0.01
and Max = 0.01
As this function is to shake the users screen, its just finding a random value between Min, -Min and Max, -Max for camera position, then just tweeting using a tween function I made.
xyz Hang on, here is actually EVERYTHING related, my bad the previous one was actually just a snippet
var shakeList = {}
func Shake(camera, data):
shakeList[data["name"]] = data #Add shake into shakeList (with all of its data)
var index = shakeList[data["name"]] #Get the shake in the shakeList
#Customisable stats for shake
var min = data["min"] / 100
var max = data["max"] / 100
var speed = data["speed"] #Speed = shakes/second
var originalCameraPos = camera.position
var latestX : float = 0.0
var latestY : float = 0.0
var GetNextShake = func():
while true:
var X = randf_range(min, max) * [-1, 1].pick_random()
var Y = randf_range(min, max) * [-1, 1].pick_random()
if X != latestX and Y != latestY:
latestX = X
latestY = Y
print(latestX, ", ", latestY)
break
var SingleShake = func():
print("New tween", ", pos = ", latestX, ", ", latestY)
GetNextShake.call()
#Tween camera position to new coordinate
await physics.tween({"object" : camera, "property" : "position", "final" : originalCameraPos + Vector3(latestX, latestY, 0), "time" : 1.0 / speed})
if index: #Make sure index exists
if data["mode"] is int: #This means shake has a time limit on it (Should end after x seconds)
pass
elif data["mode"] is bool: #This means shake is on toggle mode (Most likely a suttle and long shake like elevator scene)
if data["mode"] == true: #Starting a shake
print("true loop")
while index["mode"] == true:
await SingleShake.call()
camera.position = originalCameraPos
Now if you run this with a camera and Shake(camera, {"speed" : elevatorShakeSpeed, "min" : 1.0, "max" : 1.0, "mode" : true, "name" : "elevator"})
it will work and print all the results (if it's working your camera should be tweening and shaking)
Did you miss my suggestion to use more precision?
DaveTheCoder Yes but it won't make a difference to the problem. I literally just need a way to change those two variables from within the function. If you don't know, I have another solution I may need. Which is just to instead await GetNextShake.call()
and then return the result of X and Y.
However, for this I will need to figure out how to "wait" for the function to return as it's not going to return a number instantly due to the while loop.
If you know I can wait for a function to return a value before continuing the code, please let me know!
The issue here is the lambda scope, which captures the local environment. Variables are captured by value so any update doesn't apply to scope outside of the lambda; the lambda doesn't belong to the class (docs).
Why [not] just use functions defined in the class?
spaceyjase It's not lambdas per se but the way they are used as coroutines here. It's a very confusing solution on top of being buggy. And yeah, using regular class methods and properties would be preferable, and eliminating coroutines completely would be even better.
xyz I need my screen to shake in random positions but I made the GetNextShake()
function so I could get a new random position for the next shake (BUT IT CANNOT BE THE SAME AS THE PREVIOUS SHAKE) Hence why I made it a subroutine so that it wouldn't interfere with the main thread. I am getting the next shake while the current one is still moving to it's position, that way there wouldn't be any stutters or stops while the code tries to find the next shake position.
Cakestax I didn't ask about your system. The system you have is obviously causing you problems, so let's put it aside for a moment. I'm asking what effect(s) you want to produce, the final visual result you're after, a typical example. That way I can suggest you a system that may do a better job with less complications.
Cakestax Ok. I'd prefer doing this directly in _process()
, but since you started designing it with coroutines here's a coroutined version. I added attenuation as well as it's a common need for shakes.
This is a Shake class. It's a 2D version but you can easily extend it to 3D. Try it with a sprite first.
You instantiate it and call start()
with all needed parameters. It'll run as a coroutine until time is up or you explicitly call stop()
class_name Shake extends RefCounted
var run = false
func start(node, pivot, amplitude, speed, duration, attenuation = 1.0):
run = true
var time = 0.0
var direction = Vector2.from_angle(randf_range(0, PI*2.0))
while(run):
# calculate camera position to tween to
direction = direction.rotated(randf_range(PI/2.0, PI*3.0/2.0)) # rotate direction vector by random angle in range 90-270 deg
var shake_offset = direction * amplitude * (1.0 - attenuation*time/duration) # multiply direction by (attenuated) amplitude
var shaken_pos = pivot + shake_offset # absolute offset position
# tween it and wait for tween to finish
var t = node.get_tree().create_tween()
t.tween_property(node, "position", shaken_pos, node.position.distance_to(shaken_pos) / speed )
await t.finished
# did we reach time limit?
time += t.get_total_elapsed_time()
if time > duration:
break
# reset to pivot position after the shake is done
node.position = pivot
func stop():
run = false
Test usage from a sprite node:
extends Sprite2D
var s
func _input(e):
if e is InputEventMouseButton and e.is_pressed():
if e.button_index == MOUSE_BUTTON_LEFT:
s = Shake.new()
s.start(self, self.position, 10, 800, 2)
if e.button_index == MOUSE_BUTTON_RIGHT:
s.stop()