Quick Links: Download Gideros Studio | Gideros Documentation | Gideros community chat | DONATE
How to make a bitmap follow mouse? — Gideros Forum

How to make a bitmap follow mouse?

Hi.

I'm trying to make the bitmap follow my mouse movement. I don't want it to move if the distance to mouse where less than a treshold (say 20px).

Any snippet on how to do it?

Regards.

Comments

  • rrraptorrrraptor Member
    edited December 2019 Accepted Answer
    local cos,sin=math.cos,math.sin
    function angle(x1,y1, x2,y2)
    	return math.atan2(y2-y1, x2-x1)
    end
     
    function distance(x1,y1, x2,y2)
    	return (x2-x1)^2+(y2-y1)^2
    end
     
    function lerp(a, b, t)
    	return a + t * (b - a)
    end
     
    FollowSprite = Core.class(Sprite)
     
    function FollowSprite:init(speed, color, distance)
    	self.g = Pixel.new(color, 1, 32, 32)
    	self.g:setAnchorPoint(.5,.5)
    	self:addChild(self.g)
    	self.tx = 0
    	self.ty = 0
    	self.speed = speed
    	self.dist = distance
    end
     
    function FollowSprite:follow(x, y)
    	self.tx = x
    	self.ty = y
    end
     
    function FollowSprite:update(dt)
    	local x, y = self:getPosition()
    	local distSq = distance(x, y, self.tx, self.ty)
     
    	if (distSq > self.dist^2) then 
    		local t = 0.1
    		x = lerp(x, self.tx, t)
    		y = lerp(y, self.ty, t)
    		self:setPosition(x, y)
    		local a = angle(x, y, self.tx, self.ty)
    		self:setRotation(^>a)
    	end
    end
     
    function FollowSprite:update2(dt)
    	local x, y = self:getPosition()
    	local distSq = distance(x, y, self.tx, self.ty)
     
    	if (distSq > self.dist^2) then 
    		local a = angle(x, y, self.tx, self.ty)
    		local dx = cos(a) * self.speed * dt
    		local dy = sin(a) * self.speed * dt
    		x += dx
    		y += dy
    		self:setRotation(^>a)
    		self:setPosition(x, y)
    	end
    end
     
    local obj = FollowSprite.new(300, 0xff0000, 20)
    stage:addChild(obj)
     
    local obj2 = FollowSprite.new(300, 0x00ff00, 20)
    stage:addChild(obj2)
     
    stage:addEventListener(Event.ENTER_FRAME, function(e)
    	local dt = e.deltaTime
    	obj:update(dt)
    	obj2:update2(dt)
    end)
    stage:addEventListener(Event.MOUSE_HOVER, function(e)
    	obj:follow(e.x, e.y)
    	obj2:follow(e.x, e.y)
    end)


    EDIT:
    You can add noise to make it move "randomly" around given point :smile:


    Noise code (refernce):
    local tmp = {
    	{1,1,0},{-1,1,0},{1,-1,0},{-1,-1,0},
    	{1,0,1},{-1,0,1},{1,0,-1},{-1,0,-1},
    	{0,1,1},{0,-1,1},{0,1,-1},{0,-1,-1}
    }
    local grad3 = {}
    -- make 0 based indices
    for i,t in ipairs(tmp) do
    	local gr = {}
    	for j = 1, 3 do 
    		gr[j-1]=t[j]
    	end
    	grad3[i-1]=gr
    end
    tmp = nil
     
    local p =  {151,160,137,91,90,15,
    	131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
    	190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
    	88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
    	77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
    	102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
    	135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
    	5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
    	223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
    	129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
    	251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
    	49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
    	138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
    }
     
    local perm = {}
    for i=0, 511 do perm[i] = p[(i & 255) + 1] end
     
    local function dot(g, x, y, z) 
    	return g[0]*x + g[1]*y + g[2]*z;
    end
     
    local function mix(a, b, t)
    	return (1-t)*a + t*b
    end
     
    local function fade(t)
    	return t*t*t*(t*(t*6-15)+10);
    end
     
    local function noise(x, y, z)
    	-- Find unit grid cell containing point
    	local X = (x//1)
    	local Y = (y//1)
    	local Z = (z//1)
     
    	-- Get relative xyz coordinates of point within that cell
    	x -= X
    	y -= Y
    	z -= Z
     
    	-- Wrap the integer cells at 255 (smaller integer period can be introduced here)
    	X = X & 255
    	Y = Y & 255
    	Z = Z & 255
     
    	-- Calculate a set of eight hashed gradient indices
    	local gi000 = perm[X+perm[Y+perm[Z]]] % 12
    	local gi001 = perm[X+perm[Y+perm[Z+1]]] % 12
    	local gi010 = perm[X+perm[Y+1+perm[Z]]] % 12
    	local gi011 = perm[X+perm[Y+1+perm[Z+1]]] % 12
    	local gi100 = perm[X+1+perm[Y+perm[Z]]] % 12
    	local gi101 = perm[X+1+perm[Y+perm[Z+1]]] % 12
    	local gi110 = perm[X+1+perm[Y+1+perm[Z]]] % 12
    	local gi111 = perm[X+1+perm[Y+1+perm[Z+1]]] % 12
     
    	-- Calculate noise contributions from each of the eight corners
    	local n000= dot(grad3[gi000], x, y, z)
    	local n100= dot(grad3[gi100], x-1, y, z)
    	local n010= dot(grad3[gi010], x, y-1, z)
    	local n110= dot(grad3[gi110], x-1, y-1, z)
    	local n001= dot(grad3[gi001], x, y, z-1)
    	local n101= dot(grad3[gi101], x-1, y, z-1)
    	local n011= dot(grad3[gi011], x, y-1, z-1)
    	local n111= dot(grad3[gi111], x-1, y-1, z-1)
    	-- Compute the fade curve value for each of x, y, z
    	local u = fade(x);
    	local v = fade(y);
    	local w = fade(z);
    	-- Interpolate along x the contributions from each of the corners
    	local nx00 = mix(n000, n100, u);
    	local nx01 = mix(n001, n101, u);
    	local nx10 = mix(n010, n110, u);
    	local nx11 = mix(n011, n111, u);
    	-- Interpolate the four results along y
    	local nxy0 = mix(nx00, nx10, v);
    	local nxy1 = mix(nx01, nx11, v);
    	-- Interpolate the two last results along z
    	local nxyz = mix(nxy0, nxy1, w);
     
    	return nxyz;
    end
     
    return noise


    And thats how you can use it with code above:
    -- add 
    --	self.x = 0
    --	self.y = 0
    -- to init function of FollowSprite
    function FollowSprite:update3(dt)
    	local x, y = self.x,self.y--self:getPosition()
    	local distSq = distance(x, y, self.tx, self.ty)
    	local n1 = 0
    	local n2 = 0
    	local power = 20
    	--self.speed = math.sqrt(distSq)  * 0.75 --< dynamic speed based on distance
    	if (distSq > self.dist^2) then 
    		local a = angle(x, y, self.tx, self.ty)
    		local dx = cos(a) * self.speed * dt
    		local dy = sin(a) * self.speed * dt
    		x += dx
    		y += dy
     
    		--self:setRotation(^>a)
    		n1 = noise(y/100, 0.1, self.zoff) * power / 2
    		n2 = noise(0.1, x/100, self.zoff) * power / 2
    	else
    		n1 = noise(y/100, 0.1, self.zoff) * power
    		n2 = noise(0.1, x/100, self.zoff) * power
    	end
     
    	self:setPosition(x + n1, y + n2)
    	self.zoff += dt
    	self.x = x
    	self.y = y
    end
    movement.gif
    393 x 230 - 124K
    +1 -1 (+4 / -0 )Share on Facebook
  • For some reason I decided to create a noise plugin :smiley:

    And after a few hours, its working, and its x5 times faster than lua version.
    But it only works for windows, cuz idk how to build for other platforms ¯\_(ツ)_/¯
    2noise.gif
    849 x 739 - 1M

    Likes: MoKaLux, talis

    +1 -1 (+2 / -0 )Share on Facebook
  • hgy29hgy29 Maintainer
    if you make it public, I can add it to gideros distributon as well as port it to other platforms
    +1 -1 (+2 / -0 )Share on Facebook
  • rrraptorrrraptor Member
    edited December 2019
    hgy29 said:

    if you make it public, I can add it to gideros distributon as well as port it to other platforms

    The question is, does someone need it? Maybe it should have more than just simplex and perlin noises :smile: Maybe something like this: https://github.com/Auburns/FastNoise
    If so, I can also create a few examples :wink:

    Likes: SinisterSoft

    +1 -1 (+1 / -0 )Share on Facebook
  • +1 for this to happen :)

    Likes: plicatibu

    my growING GIDEROS github repositories: https://github.com/mokalux?tab=repositories
    +1 -1 (+1 / -0 )Share on Facebook
  • +1!
    > Newcomers roadmap: from where to start learning Gideros
    "What one programmer can do in one month, two programmers can do in two months." - Fred Brooks
    “The more you do coding stuff, the better you get at it.” - Aristotle (322 BC)
  • @rrraptor That's exactly what I wanted. It is amazing.

    Thank you for sharing.

    And please, let your code be added to Gideros.

    Regards.

    Likes: MoKaLux

    +1 -1 (+1 / -0 )Share on Facebook
  • Yes, Gideros needs more general purpose things like this.

    Likes: Apollo14

    +1 -1 (+1 / -0 )Share on Facebook
  • hgy29hgy29 Maintainer
    You can use C++, it is can cooperate with C code
  • rrraptorrrraptor Member
    edited December 2019
    hgy29 said:

    You can use C++, it is can cooperate with C code

    Ok, good :smile:
    So, how to properly create a binding?

    The way I did it is:
    Define noise variable
    static FastNoise noise;
    Create instance:
    static void g_initializePlugin(lua_State* L)
    {
    	noise = FastNoise();
    	// rest of the code
    }
    And the binding functions like that:
    static int GetNoise(lua_State* L)
    {
    	FN_DECIMAL x = lua_tonumber(L, -1);
    	FN_DECIMAL y = lua_tonumber(L, -2);
    	FN_DECIMAL z = lua_tonumber(L, -3);
     
    	FN_DECIMAL v = noise.GetNoise(x, y, z);
     
    	lua_pushnumber(L, v);
     
    	return 1;
    }
    g_deinitializePlugin is empty, cuz idk how to destroy static instance, google says that it will be automatically destroyed.
    Also, should I to use lua_pop every time Im getting/pushing values from/to stack?

    Or I need to use g_createClass ?
  • hgy29hgy29 Maintainer
    if You don’t need to instanciate your generator, you won’t need to create classes. For basic lua C interface, take a look at how it is done for other plugins in gideros
Sign In or Register to comment.