Click on game object

Hey there.
I am new to lua and defold (not new in programming ;))

I got some trouble handling couple of gameobjects while clicking on it.
I have x gameobjects instanciated with a script attached that handles the ON_INPUT

function on_input(self, action_id, action)
   if action.released then
      if action_id == hash("clicked") then -- clicked is defined in input.bindings for the left-mousebutton
         ACTIVEOBJECT = go.get_id()
         print(ACTIVEOBJECT)
      end
   end
end

If I do so, ALL gameobjects are printing their own ID. WTF?

I also read something about the return-value of ON.INPUT. Tried to return FALSE or TRUE. If I use TRUE it just prints the FIRST object in hierachy.

the question is: how to solve that only the really clicked object is the ACTIVEOBJECT.

Sure, I could write some code who checks the clicked coordinates comparing to the coordinates of the GOā€¦but isnt there a easier / more professional way? collision?

oh by the wayā€¦ all the prints are also in the log if I just click somewhere (not an any GO)

Yes, that is by design. Any script that listens to input will receive all input - unless a script before it in the input stack consumes it (by returning true).

If you need to detect a click on a certain object you need to (as you suggest) check clicked coordinates against object location. Alternatively you can use physics collisions. Whatā€™s best depends on your case.

I have an example of this where I take into account game object scale, sprite scale and so on:

Try it: http://britzl.github.io/publicexamples/click_game_object/index.html
Code: https://github.com/britzl/publicexamples/tree/master/examples/click_game_object

And I have an example of this approach as well (click and drag):

Try it: http://britzl.github.io/publicexamples/click_and_drag/index.html
Code: https://github.com/britzl/publicexamples/tree/examples/click_and_drag

4 Likes

Thanks for your answers.
I thought it would be a little more handy than checking against coords o.o :wink:

maybe the collision is more useful in my first project. Have to check that.

Hey @britzl,
first, thanks for all of your examples! I am studyiing them. But, lot of them I cant download at once (one zip file). Why? Some projects are downloadable in one simple zip file, others dont have that nice CLONE AND DOWNLOAD button.

(maybe I am too stupid for?)

1 Like

The master repo of my examples project contains multiple projects in a single repository. Each project is in a separate folder in examples, with a main collection etc. This approach with multiple small examples in one project will be changed as soon as the new editor is released and supports bundling.

@britzl dont understand that git-things :smiley:

I am already on that problem. Iā€™ve tried different sollutions. Collisions etc. but I got stuck on all them.
Now I am on the ā€œcoordinate-comparingā€. Seems easy and logic. Seemsā€¦but maybe you can explain me result of the following code :slight_smile:


go.property("maxhitpoints", 100)
go.property("hitpoints", 100)
go.property("maxenergy", 100)
go.property("energy", 100)
go.property("energyreload", 1)
go.property("energyreloadspeed", 1)
go.property("moveenergy", 10)
go.property("movespeed", 5)
go.property("ammo", 0)


local COLLISION_RESPONSE = hash("collision_response")
local RIGHTCLICKED = hash("rightclicked")
local LEFTCLICKED = hash("clicked")
local INPUT = hash("input")
local targetpos = nil
local pos = nil 
local active = false

function init(self)
	-- Add initialization code here
	-- Remove this function if not needed
	msg.post(".", "acquire_input_focus")
	pos = go.get_position()
	active = false
end


function update(self, dt)
	-- Add update code here
	-- Remove this function if not needed
	--[[
	if self.move and active then
		local movetime = math.abs((targetpos.x - pos.x) + (targetpos.y - pos.y))  / self.movespeed			
		go.animate(go.get_id(),"position", go.PLAYBACK_ONCE_FORWARD, targetpos, go.EASING_LINEAR, movetime)
		--go.set_position(targetpos)
		self.move = false
		self.active = false
	end	
	]]
	
	if active then
		print(go.get_id())
		go.set("#sprite", "tint.w", 1.0)
	else
		go.set("#sprite", "tint.w", 0.5)
	end	
end

function on_message(self, message_id, message, sender)
	if message_id == hash("activated") then
		print("CROSSHAIR CLICKED ON ME " .. go.get_id())
		--self.active = true
	end
end

function on_input(self, action_id, action)
	pos = go.get_position()
	--local quat = vmath.quat_rotation_z(angle)
	
	if action.released then		
		targetpos = vmath.vector3(action.x , action.y , 0)	

			if active then
				print("POS " .. pos)
				print("TARGET " .. targetpos)
				self.move = true
			end

			print("---" .. go.get_id())
			print(" math x: " .. math.abs(targetpos.x - pos.x))
			print(" math y: " .. math.abs(targetpos.y - pos.y))
		
		if math.abs(targetpos.x - pos.x) < 32 and math.abs(targetpos.y - pos.y) < 32 then

			active = true
			print("ACTIVATED CLICKED IN MY BOX " .. go.get_id())
		else
			active = false
		end	
		

	end	
end

Iā€™ve attached this script it to all the units (gameobjects with sprites, collision etc named COLLECTOR, TANK, ROCKETLAUNCHER for example). 3 Iā€™ve added to the scene for testing.

Goal should be: clicking on a unit it will activating THIS UNIT for doing something like moving or popping up a menu.
To check that, Iā€™ve easily added the code in the UPDATE function witch tints ITSELF 100% and 50% if not active.

Now the magic!
if you click on ONE ā€œspecialā€ unit (always the same (in my project its the COLLECTOR) 1st in the list of the OUTLINE - maybe thats the reason??) and tadaaaā€¦ ALL 3 units are 100% shown. the other 2 units are never tint 100%.
But a look in the debug.log shows the correct output which one is active.

I hope my problem is clearly enough to understand (and my germany-english good enough :smiley:)

oh by the way: ignore the ON_MESSAGE thingā€¦ that message is also shown sended from the mouse/crosshair. but it has no function in that case.

And if you uncomment the move-stuff in UPDATE it will get more confuzius :slight_smile:

update:
If used self.active in the whole script instead of just active. the activation (highlighting) is working now.
Question to LOCAL definition: If i define a variable like LOCAL active at the beginning (not in any class or method), the variable will be used for the whole project (like public / global)??? Maybe thats the reason for?

if notā€¦
if there is a way to have a global variable for all scripts and gameobjects?

There is a section in the lua manual on variable scopes: http://www.defold.com/manuals/lua/#_locals_globals_and_lexical_scoping

Local vars are shared between every instance of the script. Use self properties if you want a variable only for that specific instance.

3 Likes

Thanks @ross.grams. Thats exactly what I needed to know :slight_smile: and explains where the problems in my scripts are located. I thought local is really local (to the script) like in other languages.

So thats the way I can define a ā€œglobal to all instances of this scriptā€-variable :slight_smile: kind of global :slight_smile:
This is - in my case - an easy way to define a global variable for the only-one-active-object.

but, if Iā€™ll define a var in a function with LOCAL it will be really local to that function, right?

Yes, the ā€œlocalā€ keyword means local to the scope you define the variable in. Inside a function, for-loop, anything between ā€œdo/thenā€ and ā€œendā€.

I would not recommend that you acquire_input_focus for all your units. At least not if you have many of them. There is a limit (16 I think) on the number of scripts that can have focus at a time. Iā€™d recommend that you have one master script that takes care of input and holds a list of all units and possibly forwards the input data or in some other way processes it before sending an action to the affected unit(s).

Thanks for that hint, @britzl!

Meanwhile I took a deeper look in GAME.PROJECT and I saw all the limitations. Now I am a little scared :wink:
A limit of 128 sprites? Really? Whats the ā€œrealā€ limit. I am working with 32px tiles, also for the random map. By a grid of 100x100 tiles? that could be too much maybe :wink:

If the input-focus is limited my way of solution surely will be a problem! Thanks for the hint. Iā€™ll manage this with the mousepointer and send a msg.post to the unit. means recoding :slight_smile:

Those are default limits. You set those because the engine allocates memory for them up front. If you need 2000 sprites, it is perfectly fine to increase that value. What will happen is that more memory will be allocated for the sprites when the game starts.

Also, note that tiles in a tilemap are not sprites.

I did a test a while back. If I recall correctly there is a hard upper cap of 32k game objects or something like that. Iā€™m sure we could increase that number if we want to but I donā€™t really see a point beyond doing some kind of FPS benchmark.

Iā€™ve added PNG files to the project and made an atlas of it, then, I add gameobjects and sprites to it. these are no sprites?

Yes. Each sprite component is a sprite.

I am also on a map with random tiles. 32x32px.

Iā€™ve created for each variation of tile a GO with a sprite (from an atlas).

The map may be 1000x1000 or so. do I have to increase the sprites up to 1000000?

I tried with 100 by 100. First error sprit-limit. After increasing, next error: GO limit.

Do I have to increase that also? Does this make sence or is there a better way to draw and calculate a map/level with random tiles?

Canā€™t you use a tilemap?

hey @sicher.
thanks for your reply. SURE! I was blind, thought to do it in this way. After creating a map with few thousand of GO it went up to 2gb ram :smiley: :smiley: :smiley:
Now I try my best with tilemaps :slight_smile:

Have to read the manual for.

3 Likes