How to best rotate a beam towards a point while maintaining a fixed origin?

I’m trying to draw a line (beams) starting from a fixed location to the coordinates of a mouse click. After trying several methods, I see that scaling a sprite from the location towards the coordinate is probably the easiest way. So I achieve this via:

local beamInstance = factory.create('/beamInstance#beamFactory', vmath.vector3(640, 65, 0))

-- Stretch beam out to mouse click location on Y axis
local beamPosition = go.get(beamInstance, 'position')
local distance = beamPosition.y - action.y

go.set(beamInstance, 'scale.y', distance)
go.set(beamInstance, 'position.y', beamPosition.y - distance / 2) -- offset

The end result looks like this:

However when I rotate this beam towards the mouse click, the origin point of the beam also moves.

angle = math.atan2(action.x - beamPosition.x, beamPosition.y - action.y)
go.set(beamInstance, 'rotation', vmath.quat_rotation_z(angle))

Resulting in this:

What would be the best way to achieve rotation in this case while maintaining a fixed origin position?

I’m attaching the playground I created for this example in case anyone ones to load it up.

BeamTest.zip (629.2 KB)

Thanks!

Try setting the y pos of your sprite (not gameobject) that contains the red beam to half the height of the image assigned to it.

You can try using a custom pivot for the beam that is located in the box position. To achieve this you can create a root gameobject in the box position and inside it you have to put the beam gameobject, now if you rotate the root gameobject everything should work as intended.

@TheKing0x9 I have an offset operation like you mentioned on the game object, are you suggesting doing it on the sprite instead?

@Attilix I’ve tried this but rotating the container (root) game object also rotates the beam game object so the result ends up being identical. If I keep the child container manually at 0 rotation every time I rotate the container, the beam doesn’t rotate at all. So wrapping it in another container doesn’t seem to effect how the child beam object works, am I missing something?

I was curious so I checked the code, the problem is that you set a different y coordinate to not show the down part of the laser

Yeah, otherwise the beam scales in two different directions on the y axis. The offset was there to make it so that it scales only in one direction and that it’s y position stays the same.

Exactly. :slight_smile:

I see, unfortunately I don’t think it’s possible to set the position of a sprite in Defold at runtime.

A couple of things:

You need to take into account both the X and Y components of the vector between the origin and mouse click.

Also, the sprite needs offsetting by 0.5 on the y-axis so that it will only scale in one direction.

Modified project attached with those two changes.

BeamTest_fix.zip (629.1 KB)

4 Likes

This works really well, I can’t thank you enough Ben! I see my mistake in not accounting for both axes in the calculation. vmath.length() is really useful in this case.

The offset works brilliantly as well, although I still quite don’t get why offsetting the sprite by 0.5 on the y-axis prevents the game object scaling to two directions. I couldn’t find any explanation for this in the docs so I’d appreciate if someone could shed some light on this.

Scaling works outward from the origin. By default, a sprite’s origin is in it’s middle so it will scale into the negative axis as well as positive. By moving the sprite so it’s bottom edge is at 0 on the y-axis, it will only scale into the positive axis.

1 Like

Don’t know if this is helpful but here’s an old laser example I made

LaserExample.zip (4.0 KB)

6 Likes

After looking at the laser script. It seems to leverage a side effect of the game engine.

My first thought was that when scaled, a laser beam would grow in two directions from its GO’s center.

However, the center of a 1 pixel wide image must lie on one side of the image or the other. This allows the laser to grow.

That’s counterintuitive in a 3d engine based on floating point coordinates. The center could be between pixel locations. I checked my theory by adding 0.5 to one of the laser’s x value. The beam continued to grow in one direction.

What do I need to know, to understand this behavior?

It is not the image itself that is being scale but the GO’s transform which is being changed. Since the sprite is offset from origin of the parent GO, it can be made to scale as if you were stretching it from one point to another. You can test this by duplicating the sprite on one of the laser GOs and moving it to the opposite side of the GO’s origin, and then it will appear to scale in the opposite direction of the laser in the same kind of way. This is more obvious when you change the color of the second sprite.

2021-01-07%2013_45_30-How%20to%20best%20rotate%20a%20beam%20towards%20a%20point%20while%20maintaining%20a%20fixed%20origin_%20-%20Qu

If you meant something else then it was not perfectly clear to me.

The sprites are not offset from the GO. That’s what’s confusing me.

Copy paste the X position / drag it to the right and it will show the offset. The size for those inputs could use adjustment.

1 Like

Got it! (darn laptop screen : - )

1 Like