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


#1

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!


#2

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.


#3

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.


#4

@kashyapaayush32 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?


#5

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


#6

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.


#7

Exactly. :slight_smile:


#8

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


#9

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)


#10

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.


#11

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.


#12

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

LaserExample.zip (4.0 KB)