Reactor Defence (a game for CoronaDefold game jam)

Hi, guys! I am currently working on the game for CoronaDefold game jam and at last I have a slightly playable prototype with main gameplay logic :slight_smile: By the way, this is my first game which I’ve programmed :slight_smile:

Gameplay notes:

  1. Main goal is to kill mobs before they reach the reactor;
  2. Turrets consume energy;
  3. Turrets do not work without energy;
  4. Reactor generates energy;
  5. Mobs deal damage to the reactor when they get to it

What one can do already:

  1. Build and upgrade turrets by clicking on them (first turret costs 20, second 80, etc). More powerful turrets do more damage. Turrets may be improved up to fifth level;
  2. Upgrade reactor. The price is shown near it. More powerful reactor generates more energy.

What one can’t do yet:

  1. Win :smiley:
  2. Lose (you’ll see a message “YOU LOSE” on the screen actually, but game will not stop)

TODO:

  1. GUI (what are the best dependencies for this? Found few, but have not tried yet. Or it better to made it from scratch? I want to make few buttons to appear near turret when user clicks it. Buttons: upgrade, on/off, special. And also move debug info (all the blue text) to GUI)
  2. Win/Lose screens
  3. Few levels
  4. Few new enemies
  5. Adjust resolution

If you have any feedback, I’ll be really really glad to hear it!

Link once more: https://denischera.com/reactor_defence2/index.html
Community page: https://www.defold.com/community/projects/76682/
Itch: https://dener.itch.io/reactor-defence

PS. Defold community is awesome! Thank you for answering my questions about engine :stuck_out_tongue:

12 Likes

Sweet! Nice work so far!

Another thing you could add to your To-do is replace the render debug text with actual label components. That way you can customize the color, font, etc.(and you don’t have to tell it to draw every frame.) That dark blue is pretty hard to read on a black background.

3 Likes

Yes, sure. For now, this info just for debug purposes. I plan to move it to GUI (already in TODO).

Awesome work! Well done for your first game!

3 Likes

I’m working on a Make_button() function. Actually, I finished it, but it’s not optimized. You can use it to your advantage.

-- Insert this into your UI script

local buttons = 0
local listButtons = {}
local listBoxes = {}
local listOwners = {}
local thisBtn = {}

function on_message(self, message_id, message, sender)
	if message_id == hash("Make_button") then
		print("ORDERED BUTTON .............................")
		make_button(sender,message[1],message[2],message[3],message[4],message[5])
	end
end

function on_input(self, action_id, action)
	if action_id == hash("lClick") then
		for i=1,buttons,1 do
			if listBoxes[i] ~= nil and listBoxes[i] ~= Deleted then
				local size = gui.get_size(listBoxes[i])
				thisPos = gui.get_position(listBoxes[i])
				cX = thisPos.x - (size.x / 2)
				cX_ = thisPos.x + (size.x / 2)
				cY = thisPos.y - (size.y / 2)
				cY_ = thisPos.y + (size.y / 2)
				if action.x >= cX and action.x <= cX_ then
					if action.y >= cY and action.y <= cY_ then
						gui.delete_node(listButtons[i])
						gui.delete_node(listBoxes[i])
						listButtons[i] = nil
						listBoxes[i] = nil
						thisBtn[1] = i
						msg.post(listOwners[i], "Button_press", thisBtn)
						print("CLICKED: " .. tostring(listOwners[i]) .. "/Button: " .. i)
					end
				end
			end
		end
	end
end

function make_button(owner,text,chars,font,pos,bound) -- Owner, Text, (Size of each character in pixels), pos, size of button in vmath.vector3() format.
	print(tostring(owner) .. " ORDERED BUTTON")
	buttons = buttons + 1
	if bound == nil then
		bound = vmath.vector3(0,0,0)
		bound.x = chars * (string.len(text) + 10)
		bound.y = 4 * chars
	end
	buttonBox = gui.new_box_node(pos,bound)
	button = gui.new_text_node(pos,text)
	set_anchor_gui({buttonBox,button},pos)
	gui.set_color(buttonBox,vmath.vector4(.7,.7,.7,1))
	gui.set_color(button,vmath.vector4(1,1,1,1))
	listBoxes[buttons] = buttonBox
	listButtons[buttons] = button
	listOwners[buttons] = owner
	gui.set_font(button,font)
	local tab = {buttons}
	msg.post(owner, "Made_button", tab)
	print("MADE BUTTON: " .. buttons)
end

-- Insert this into a module, and have your script using the make_button() function require that mod.

function on_button_message(message_id, message, btnHash, thisBtnNums)
	if message_id == hash("Made_button") then
		btnHash = btnHash + 1
		thisBtnNums[btnHash] = message[1]
		return "made"
	elseif message_id == hash("Button_press") then
		return "press"
	end
end
-- As an example
-- /main/objects/turret

require "/main/[]" -- [] = wherever you store the on_button_message module

local btnHash = 0
local thisBtnNums = {}

function update(self,dt)
    if click_turret == true and once == false then
        once = true
        list = {"Upgrade", GETfont_size(font), font,vmath.vector3(100,300,0), nil}
	    msg.post("[]", "Make_button", list) -- [] = wherever your UI script is with the Make_button() function.
        list = {"On/Off", GETfont_size(font), font,vmath.vector3(100,200,0), nil}
	    msg.post("[]", "Make_button", list)
        list = {"Special", GETfont_size(font), font,vmath.vector3(100,100,0), nil}
	    msg.post("[]", "Make_button", list)
    end
end

function on_message(self, message_id, message, sender)
	if on_button_message(message_id,message,btnHash,thisBtnNums) == "made" then
	elseif on_button_message(message_id,message,btnHash,thisBtnNums) == "press" then
		if message[1] == thisBtnNums[1] then -- This would correlate to the order of the created buttons. Upgrade is thisBtnNums[1], On/Off is [2], Special is [3]
			turret_level = turret_level + 1
        elseif message[1] == thisBtnNums[2] then
           -- .... Etc.
		end
	end
end

Let me know if you have any issues. I did my best to correctly tie everything together, but there may have been a few things I missed. Good luck!

Also, as feedback, I noticed the game seemed to slow in 2 second intervals. 2 seconds normal, 2 seconds slow.

2 Likes

Completely agree – really well done!

3 Likes

Thanks. What’s your specs? Android/Win/Mac/etc… Browser? I also noticed low performance of Defold games in general on my old old Win XP :smiley:

PS. I definitely will check your code with buttons! Thanks!

1 Like

Only thing old would be my HDD. Formatted within the last few years.

Windows 7
Chrome Browser
AMD FX 4300 Quad Processor
10GB Ram
Radeon 460 Graphics Card

Should process this like butter.

That’s strange then. I’ve tested it in Chrome - same thing. But after refreshing the page - everything’s okay. There is also strange behavior of spawning mobs. The game lags, slowing their speed, but timer which counting to generate new ones - doesn’t lag so at the end there are more mobs with less space between them.

I have a timer which spawns mobs every 1.5 secs (I also have three more timers - one just counts time; another spawns mobs of 2 lvl every 5 secs after 10 secs (that’s third timer, which is not repeating one) from start). Maybe that’s the case of lags?

In FF everything’s fine.

There is also interesting thing. If you alt-tab to another window or tab and forget about the game for a while, you’ll see tons of mobs one on top of the another.

Well, if you’re planning on developing this for Andriod/IOS I wouldn’t worry about that. Your main goal would be to get the game done for those platforms. Then worry about this if you want to go further.

But yes, I agree. This is very strange. Did you use the Native Timer Extension by Britzl? If so, I’d notify him of the find.

Thanks. Yes, that’s native timer of @britzl

1 Like

Here are some updates:

  1. Resolution fixed a bit (thanks to Orthographic extension) But that’s still not perfect. Working with resolution-stuff is really painful in Defold :frowning:
  2. Energy and money stuff moved to labels as ross.grams suggested. Tried to make it with GUI but GUI elements are messed up if window is stretched. I am afraid, it will be hard to implement buttons with GUI, but we’ll see.
  3. Now HP of mobs displayed not with numbers, but with sprites. :slight_smile:
  4. Music added.

Link.

UPD: Don’t know why, but it lags hard in Chrome. :frowning:

1 Like

Nice Little game :slight_smile: Tower defence.

I am very impressed how “new developer” are able to do such nice Little games thumbs up. If I take a look at my poor games :frowning:

I’ve played it on the way to unlimited :slight_smile: no enemy reached the reactor. dead at 2nd line. Money and energy grows. :slight_smile:
…upgraded the first 2 lines of defence to max…energy went out … just for fun :slight_smile:

3 Likes

Thanks! :slight_smile: The game is not done yet, so yes - there will be some work on balance.

1 Like

Infinite Setup. last line of defence not needed anymore (just at the beginning) :slight_smile:
Harder enemies needed :wink:

1 Like

Did you check the Release checkbox when bundling for HTML5? Non-release builds will be very slow in Chrome.

1 Like

Checked the checkbox and everything seems okay now. Thanks! :slight_smile:

UPD: Hm… Or not… I don’t quite sure. It seems that in Chrome mobs move little bit slower. It’s better than before, but not the same as in Firefox. Maybe problem is in my PC, don’t know.

  1. …I am afraid, it will be hard to implement buttons with GUI, but we’ll see.

Were you able to use the make_button function, or did you figure this out after testing gui yourself? I’m curious because I hope the make_button function didn’t give you trouble :wink: .

GUI with your code is next thing I want to implement :slight_smile: Hope to finish it next few days. :wink:

I do not fully understand your code. Can you help a little bit please?

  1. So, first I’ve made GUI.go with GUI.gui and attached GUI.gui_script to it. All files are in /main/GUI. Added GUI.go to main.collection. Am I right that I don’t need to change anything in this file? (Except of hash(“lClick”) to hash(“LMB”))

GUI.gui_script:

local buttons = 0
local listButtons = {}
local listBoxes = {}
local listOwners = {}
local thisBtn = {}

function on_message(self, message_id, message, sender)
	if message_id == hash("Make_button") then
		print("ORDERED BUTTON .............................")
		make_button(sender,message[1],message[2],message[3],message[4],message[5])
	end
end

function on_input(self, action_id, action)
	if action_id == hash("LMB") then
		for i=1,buttons,1 do
			if listBoxes[i] ~= nil and listBoxes[i] ~= Deleted then
				local size = gui.get_size(listBoxes[i])
				thisPos = gui.get_position(listBoxes[i])
				cX = thisPos.x - (size.x / 2)
				cX_ = thisPos.x + (size.x / 2)
				cY = thisPos.y - (size.y / 2)
				cY_ = thisPos.y + (size.y / 2)
				if action.x >= cX and action.x <= cX_ then
					if action.y >= cY and action.y <= cY_ then
						gui.delete_node(listButtons[i])
						gui.delete_node(listBoxes[i])
						listButtons[i] = nil
						listBoxes[i] = nil
						thisBtn[1] = i
						msg.post(listOwners[i], "Button_press", thisBtn)
						print("CLICKED: " .. tostring(listOwners[i]) .. "/Button: " .. i)
					end
				end
			end
		end
	end
end

function make_button(owner,text,chars,font,pos,bound) -- Owner, Text, (Size of each character in pixels), pos, size of button in vmath.vector3() format.
	print(tostring(owner) .. " ORDERED BUTTON")
	buttons = buttons + 1
	if bound == nil then
		bound = vmath.vector3(0,0,0)
		bound.x = chars * (string.len(text) + 10)
		bound.y = 4 * chars
	end
	buttonBox = gui.new_box_node(pos,bound)
	button = gui.new_text_node(pos,text)
	set_anchor_gui({buttonBox,button},pos)
	gui.set_color(buttonBox,vmath.vector4(.7,.7,.7,1))
	gui.set_color(button,vmath.vector4(1,1,1,1))
	listBoxes[buttons] = buttonBox
	listButtons[buttons] = button
	listOwners[buttons] = owner
	gui.set_font(button,font)
	local tab = {buttons}
	msg.post(owner, "Made_button", tab)
	print("MADE BUTTON: " .. buttons)
end
  1. Created on_button_message.lua in /main/GUI

on_button_message.lua:

function on_button_message(message_id, message, btnHash, thisBtnNums)
	if message_id == hash("Made_button") then
		btnHash = btnHash + 1
		thisBtnNums[btnHash] = message[1]
		return "made"
	elseif message_id == hash("Button_press") then
		return "press"
	end
end
  1. My turret.script is attached to every turret.go in main.collection. Script has id = behavior_TurretReactor. For example url of second turret is /turret2#behavior_TurretReactor

I’ve added to turret.script the following:

require "/main/GUI/on_button_message"

Little question here. Should not I specify path here something like:

require "main.GUI.on_button_message"

Or both are right?

Next:

local btnHash = 0
local thisBtnNums = {}
function on_message(self, message_id, message, sender)
	if on_button_message(message_id,message,btnHash,thisBtnNums) == "made" then
	elseif on_button_message(message_id,message,btnHash,thisBtnNums) == "press" then
		if message[1] == thisBtnNums[1] then -- This would correlate to the order of the created buttons. Upgrade is thisBtnNums[1], On/Off is [2], Special is [3]
			self.state = self.state + 1
        elseif message[1] == thisBtnNums[2] then
           -- .... Etc.
		end
	end
end
function update(self, dt)
	if message_id == hash("upgrade") == true and once == false then
        once = true
        list = {"Upgrade", GETfont_size(font), font,vmath.vector3(100,300,0), nil}
	    msg.post("GUI#GUI", "Make_button", list) -- [] = wherever your UI script is with the Make_button() function.
        list = {"On/Off", GETfont_size(font), font,vmath.vector3(100,200,0), nil}
	    msg.post("[]", "Make_button", list)
        list = {"Special", GETfont_size(font), font,vmath.vector3(100,100,0), nil}
	    msg.post("[]", "Make_button", list)
    end
end	

So, what I need to fix to make all this stuff working? Tried some approaches, but it seems that I miss something. Thanks!

UPD. Also, it would be really helpful to have some minimum working prototype from you :slight_smile: Like britzl’s extensions. Your code can be really useful for others in future, but without working example it’s a bit hard to implement it (if one’s knowledge of Lua is limited).