PineScript - Keep in labels in the future when based on a fixed event - charts

Thanks to the PineCoders on Twitter for pointing me in this direction.
I'm tracking both a hard stop (based on an entry indicator) and trailing stop and would like to keep them aligned.
bar_index+5 works great for the trailing stop, but for the hard stop, it simply places it 5 bars after entry indicator.
I've tried factoring in ta.barssince and it seems to have no effect, presumably since it believes the indicator is bar_index or something... I'm at a loss.
Here's the code:
SLAlabelText = str.tostring(SLCalc, "#.##")
var SLALabel = label.new(x = bar_index, y = SLCalc, color = color.red, style = label.style_none, textcolor = color.white, text=SLAlabelText)
if longBoy and stopLossA
label.set_xy(SLALabel, x = bar_index+5, y = SLCalc)
label.set_text(SLALabel, SLAlabelText)
label.set_tooltip(SLALabel, "Stop Loss: " + SLAlabelText)
"longBoy" is the indicator's confirmed state.
Chart image. Apologies for the meme stock, it was the best example.

Related

Roblox studio How do I change a TextLabel text in script

I want to make a gui that show your coordinates in game with text labels but my script seems didn't change the text at all
players = game.Players.LocalPlayer
players.CharacterAdded:Wait()
X = math.floor(players.Character.HumanoidRootPart.Position.X)
Y = math.floor(players.Character.HumanoidRootPart.Position.Y)
Z = math.floor(players.Character.HumanoidRootPart.Position.Z)
text = script.Parent.Text
while true do
text = X..","..Y..","..Z
X = math.floor(players.Character.HumanoidRootPart.Position.X)
Y = math.floor(players.Character.HumanoidRootPart.Position.Y)
Z = math.floor(players.Character.HumanoidRootPart.Position.Z)
end
please help me
I wanted to change the text to XYZ position in string
but everytime i launch the game the text didnt change
and it still at default text in roblox ui text label
The simple answer to your question of how do I change a TextLabel text is you just set the Text property.
script.Parent.Text = "Hello World"
If you want a simple way to track the changing position of a player's character, I would recommend using the Changed signal on the Part. It will fire the connected function every time the property changes, and it allows you to avoid using an infinite while-loop.
local text = script.Parent
local player = game.Players.LocalPlayer
-- wait for the player's character to exist
if not player.Character then
player.CharacterAdded:Wait()
end
-- listen for changes to the player's position
local hrp = player.Character.HumanoidRootPart
hrp:GetPropertyChangedSignal("Position"):Connect(function()
local position = hrp.Position
local x, y, z = math.floor(position.X), math.floor(position.Y), math.floor(position.Z)
-- format the position, and display it in the TextLabel
local positionString = string.format("(%d, %d, %d)", x, y, z)
text.Text = positionString
end)
So I can see that you have made few mistakes here
Explanation:
First of all, players.CharacterAdded:Wait() doesn't always work and never works in studio. So instead of that, you should use players.Character:WaitForChild("HumanoidRootPart").
Second thing. By calling text = script.Parent.Text you were requesting the text inside of it (you were getting it as a string), so to simply fix that you have to use text = script.Parent and then when changing text you will have to use text.Text = "your text".
The next one is making your while loop infinite by using bool true. You can't make it like that or else the playar may experience lag or even script may crash. So I'd suggest to put this to something like wait(0.1).
And the last thing is that you should get X,Y,Z before putting it into the text or else it will be delayed.
And your final script should be looking like this:
players = game.Players.LocalPlayer
players.Character:WaitForChild("HumanoidRootPart")
X = math.floor(players.Character.HumanoidRootPart.Position.X)
Y = math.floor(players.Character.HumanoidRootPart.Position.Y)
Z = math.floor(players.Character.HumanoidRootPart.Position.Z)
text = script.Parent
while wait(0.1) do
X = math.floor(players.Character.HumanoidRootPart.Position.X)
Y = math.floor(players.Character.HumanoidRootPart.Position.Y)
Z = math.floor(players.Character.HumanoidRootPart.Position.Z)
text.Text = X..","..Y..","..Z
end
Keep scripting, nothing is easy without practice,
KubaDC

Infinite Background problem with division SpriteKit

I've been trying to implement an infinite background animation, which should change between 4 images of equal height and then repeat the sequence. However, it does not seem to work properly.
Note anchorPoint = CGPoint(x: 0.5, y: 0)
func updateBackground(currentTime: TimeInterval){
var delta: CGFloat = 0.0
if lastUpdate != nil {
delta = CGFloat(currentTime - lastUpdate)
}
//First increment position
activeBackground1.position.y += delta*backgroundVelocity
activeBackground2.position.y += delta*backgroundVelocity
//Detect bounds surpass
if activeBackground1.position.y > activeBackground1.size.height + screen.height/2 {
lastSky = (lastSky + 1)%4
sky1 = SKTexture(imageNamed: "sky" + String(lastSky))
activeBackground1.texture = sky1
//Reposition: background1 new position is equal to minus the entire height of
//background2 + its y size.
activeBackground1.position.y = -abs(activeBackground2.size.height-activeBackground2.position.y)
}
if activeBackground2.position.y > activeBackground2.size.height + screen.height/2 {
lastSky = (lastSky + 1)%4
sky1 = SKTexture(imageNamed: "sky" + String(lastSky))
activeBackground2.texture = sky1
activeBackground2.position.y = -abs(activeBackground1.size.height-activeBackground1.position.y)
}
}
The update algorithm works fine, but when it is needed to reposition one of the two background, it seems there is an offset of about 10.0 CGFloat from one background to another. What am I doing wrong?
EDIT: It turned out that the error was located in my image, which presented some blank rows and therefore generated visualisation glitches. So my code works perfectly.
I do the test and most likely you should use something like:
activeBackground2.position.y = activeBackground1.size.height + activeBackground1.position.y
instead of
activeBackground2.position.y = -abs(activeBackground1.size.height-activeBackground1.position.y)
I did this example and it works correctly: https://github.com/Maetschl/SpriteKitExamples/tree/master/InfiniteBackground/InfiniteBackground
Feel free to see and use.
Your problem is floating point math causing rounding errors. I am on a phone right now so I can’t wrote code, but what you want to do is have 1 parent SKNode to handle your entire background.
Add your background slivers to the parent node.
You then place the moving action on the parent only.
As each sliver leaves the screen, you take the sliver, and move it to the end of the other slivers.
This jumping should always be done with integer math, leaving no holes.
Basically:
The floating point moving math is done on the parent node.
The integer based tile jumping is done on each of the slivers.

Positioning Nodes At Below the Bottom of the Screen (Spritekit)

Hello I'm trying to spawn bullets at the bottom of my screen to travel upwards but the current code that I have spawns the bullets at the top of the screen. I've tried making the height negative and nothing happened. Here's the code I'm working with, thanks.
let randomBulletPosition = GKRandomDistribution(lowestValue: -300, highestValue: 300)
let position = CGFloat(randomBulletPosition.nextInt())
bullet.position = CGPoint(x: position, y: self.frame.size.height + bullet.size.height)
Some nice conversions will help you.
Now, do not do this all the time, this should be a one and done type deal, like in a lazy property.
First, we want to get the bottom of our view
let viewBottom = CGPoint(x:scene!.view!.midX,y:scene!.view!.frame.maxY) //In a UIView, 0,0 is the top left corner, so we look to bottom middle
Second, we want to convert the position to the scene
let sceneBottom = scene!.view!.convert(viewBottom, to:scene!)
Finally we want to convert to whatever node you need it to be a part of. (This is optional if you want to place it on the scene)
let nodeBottom = scene!.convert(sceneBottom,to:node)
Code should look like this:
let viewBottom = CGPoint(x:scene!.view!.midX,y:scene!.view!.frame.maxY)
let sceneBottom = scene!.view!.convert(viewBottom!, to:scene!)
let nodeBottom = scene!.convert(sceneBottom,to:node)
Of course, this is a little ugly.
Thankfully we have convertPoint and convert(_from:) to clean things up a little bit
let sceneBottom = scene.convertPoint(from:viewBottom)
Which means we can clean up the code to look like this:
let sceneBottom = scene.convertPoint(from:CGPoint(x:scene!.view!.midX,y:scene!.view!.frame.maxY))
let nodeBottom = node.convert(sceneBottom,from:scene!)
Then we can make it 1 line as:
let nodeBottom = node.convert(scene.convertPoint(from:CGPoint(x:scene!.view!.midX,y:scene!.view!.frame.maxY),from:scene!)
As long as the node is available to the class, we can make it lazy:
lazy var nodeBottom = self.node.convert(self.scene!.convertPoint(CGPoint(x:self.scene!.view!.midX,y:self.scene!.view!.frame.maxY),from:self.scene!)
This means the first time you call nodeBottom, it will do these calculations for you and store it into memory. Everytime after that, the number is preserved.
Now that you know where the bottom of the screen is in the coordinate system you want to use, you can assign the x value to whatever your random is producing, and you can subtract the (node.height * (1 - node.anchorPoint.y)) to fully hide your node from the scene.
Now keep in mind, if your node moves between various parents, this lazy will not update.
Also note, I unwrapped all optionals with !, you may want to be using ? and checking if it exists first.

How to make a slow transition of color in sprite kit?

Hello fellow developers,
I'm trying to change the color of a circle slowly in SpriteKit, making a transition from the original color to the new one with some time between them, transitioning from one color to the other visually. The problem that I have is that my code doesn't make that change slowly, it simply changes like if I directly assigned the new color. Here's my actual code:
func changeColor(c: UIColor) {
var r:CGFloat = 0
var g:CGFloat = 0
var b:CGFloat = 0
var a:CGFloat = 0
c.getRed(&r, green: &g, blue: &b, alpha: &a)
var r1:CGFloat = 0
var g1:CGFloat = 0
var b1:CGFloat = 0
var a1:CGFloat = 0
circle.fillColor.getRed(&r1, green: &g1, blue: &b1, alpha: &a1);
let wait = SKAction.waitForDuration(0.4)
r = (r - r1)/10
g = (g - g1)/10
b = (b - b1)/10
for(var i = 0; i < 10; i++) {
let cN = UIColor(red: (r1 + r*CGFloat(i)), green: (g1 + g*CGFloat(i)), blue: (b1 + b*CGFloat(i)), alpha: 1.0)
circle.fillColor = cN
circle.strokeColor = cN
runAction(wait)
}
}
I really belive that the problem is in "runAction(wait)", but I'm not sure. I'd like to know if there's a default function that does what I want, but I highly doubt it.
The problem is that you're trying to do all of this "live" in a for loop. All the code in your function runs in between frames of animation, so that won't work.
To make this clearer, let's ignore the wait part for a moment. When you run a function that looks like this:
func changeColor() { // unrolled loop and pseudocode colors for clarity
circle.fillColor = blue
circle.fillColor = red
circle.fillColor = green
}
...SpriteKit does change the circle's color three times—immediately—but it isn't drawing the results. Whatever color you set it to most recently appears only after all your code finishes running and SpriteKit draws the screen.
When you use SKActions, what you're doing is lining up instructions for SpriteKit to follow over time, which includes instructions for tasks that take more than one animation frame. But the non-SKAction calls in your code are still the same as they were before—they make immediate changes, the end result of which you see when the next frame draws.
So, when your code looks like this:
func changeColor() { // unrolled loop and pseudocode colors for clarity
circle.fillColor = blue
circle.runAction(SKAction.waitForDuration(0.4))
circle.fillColor = red
}
... the order of events is like this:
set color to blue
add a wait action to the list of planned actions
set color to red
draw the next frame (color is red)
execute the list of planned actions (wait for 0.4 sec before executing next action in sequence)
So, the first thing to do is to get your color changes to stop being between-frames changes and add them to the over-time task list — that is, change color via an SKAction. There's a colorizeWithColor action, but I'm not sure whether it applies to shape nodes (with their separate fill/stroke colors). Try it, and if that fails you can try a runBlock
action that directly sets fillColor/strokeColor.
Back to pseudocode to talk about the sequencing problem, though...
func changeColor() { // unrolled loop and pseudocode color actions
circle.runAction(mySetBlueColorAction)
circle.runAction(SKAction.waitForDuration(0.4))
circle.runAction(mySetRedColorAction)
}
If you run this you'll notice there's still a problem here. Just calling runAction adds separate actions that run (roughly) in parallel. So your circle is still changing colors twice, but both changes are happening at the same time. (Which one wins? I'm not sure there's a determinate answer.) And at the same time as your circle is getting confused about its color, it's also starting to wait 0.4 seconds for... what exactly?
A waitForDuration action makes sense only in the context of a sequence action—for it to be meaningful, there needs to be something after in in sequence to wait for.
So, if what you want to happen sounds like this sequence:
Set the color
Wait a bit
Set the color to something else
... then what you need is a sequence action describing what you want to happen in order:
let sequence = SKAction.sequence([
mySetBlueColorAction,
SKAction.waitForDuration(0.4),
mySetRedColorAction,
SKAction.waitForDuration(0.4),
mySetGreenColorAction,
// etc.
])

World.QueryAABB giving incorrect results in libgdx

I'm trying to implement mouse selection for my game. When I QueryAABB it looks like it's treating objects much larger than they really are.
Here's what's going on in the image
The blue box is an actor containing a body that I'd like to select
The outline on the blue box is drawn by Box2DDebugRenderer
The mouse selects a region on the screen (white box), this is entirely graphical
The AABB is converted to meters and passed to QueryAABB
The callback was called for the blue box and turned it red
The green outline left behind is a separate body to check if my conversions were correct, this is not used for the actual selection process
It seems to be connected to my meter size, the larger it is, the more inaccurate the result is. At 1 meter = 1 pixel it works perfectly.
Meter conversions
val MetersToPixels = 160f
val PixelsToMeters = 1/MetersToPixels
def toMeters(n: Float) = n * PixelsToMeters
def toPixels(n: Float) = n * MetersToPixels
In the image I'm using MetersToPixels = 160f so the inaccuracy is more visible, but I really want MetersToPixels = 16f.
Relevant selection code
val x1 = selectPos.x
val y1 = selectPos.y
val x2 = getX
val y2 = getY + getHeight
val (l,r) =
if (x2 < x1)
(x2,x1)
else
(x1,x2)
val (b,t) =
if (y2 < y1)
(y2,y1)
else
(y1,y2)
world.QueryAABB(selectCallback, toMeters(l),toMeters(b), toMeters(r),toMeters(t))
This code is inside the act method of my CursorActor class. And selectPos represents the initial point where the use pressed down the left mouse button and getX and getY are Actor methods giving the current position. The next bit sorts them because they might be out of order. Then they are converted to meters because they are all in pixel units.
selectCallback: QueryCallback
override def reportFixture(fixture: Fixture): Boolean = {
fixture.getBody.getUserData match {
case selectable: Selectable =>
selected += selectable
true
case _ => true
}
}
Selectable is a trait that sets a boolean flag internally after the query which helps determines the color of the blue box. And selected is a mutable.HashSet[Selectable] defined inside of CursorActor.
Other things possibly worth noting
I'm new to libgdx and box2d.
The camera is scaled x2
My Box2DDebugRenderer uses the camera's combined matrix multiplied by MetersToPixels
From what I was able to gather, QueryAABB is naturally inaccurate for optimization. However, I've hit a roadblock with libgdx because it doesn't have any publicly visible function like b2testOverlap and from what I understand, there's no plan for there to be one any time soon.
I think my best solution would probably be to use jbox2d and pretend that libgdx's physics implementation doesn't exist.
Or as noone suggested I could add it to libgdx myself.
UPDATE
I decided to go with a simple solution of gathering the vertices from the fixture's shape and using com.badlogic.gdx.math.Intersector against the vertices of the selection. It works I guess. I may stop using QueryAABB all together if I decide to switch to using a sensor for the select box.