Early Days on my 2nd Game for Defold

It’s very very early days, but I wanted to post here so I can later track my progress and share my progress with the defold community.

I’m working on a multiplayer, roguelike, tower defense game. It’s kind of like clash royale, but instead of playing cards during the game. The roguelike element will be you choose your upgrades in between rounds and then the game plays itself during the battle, but the player will have some minor abilities to impact battle (like launch an air strike or increase defenses).

Keeping in the spirit of Kabocha Games, the year is 2235 and plants have been mutated into weapons. You have to protect your garden from the other player’s garden as they attack each other trying to destroy the other players Kabocha (pumpkin).

Each player could possibly choose the exact same upgrades as the game starts with a random upgrade selection. But based on what they select the follow on selections will be randomly generated based on the previous selection. So it’s a “fair” roguelike multiplayer game.


It’s been a while for an update. I have been struggling on some of the tower aim/bullet mechanics.

However, I think I finally have it now. The planes won’t be in the game…I’m just using them to test targeting.

I have two LUA Modules. One that tracks attributes for upgrades to towers and other objects in the game. Plus one that tracks game objects created and deleted.

My next update will focus on selecting upgrades between rounds.


How are you doing the laser? It looks like multiple game objects along a line.

Technically it’s a plasma bullet :rofl:

And the reason it looks like a lazer is the rate of fire I have it set to. If I slow it down it will look more like a bunch of bullets. A game mechanism I have is being able to upgrade things (like rate of fire, amount of ammo, damage, etc…). So this is the more high powered version of the plasma fire rate.


So here’s my system for choosing upgrades. First this is just placeholder graphics.
But I give player 4 options then if they want to reroll they can for free but then only get 2 options. And a 2nd reroll is free but then it’s only one option.

I used a LUA module I wrote with the help of ChatGPT.

-- card_picker.lua
local card_picker = {}

-- Define your card sets
card_picker.cards_tower_lvl1 = {"armor5", "attack5", "range", "speed5"}
card_picker.cards_tower_lvl2 = {"armor10", "attack10", "speed10"}
card_picker.cards_tower_lvl3 = {"armor20", "attack20", "speed20"}
card_picker.cards_Veggies = {"broccoliseed", "carrotseed", "chilipepperseed", "greenpepperseed", "onionseed", "radishseed"}
card_picker.cards_soil = {"deweed", "fertilizer", "watercan"}

-- Function to repeat items in a list based on their weight
function card_picker.repeatItems(list, times)
	local result = {}
	for _, item in ipairs(list) do
		for i = 1, times do
			table.insert(result, item)
	return result

-- Create a weighted list of all cards
function card_picker.createAllCards()
	local allCards = {}
	for _, card in ipairs(card_picker.repeatItems(card_picker.cards_tower_lvl1, 25)) do table.insert(allCards, card) end
	for _, card in ipairs(card_picker.repeatItems(card_picker.cards_tower_lvl2, 10)) do table.insert(allCards, card) end
	for _, card in ipairs(card_picker.repeatItems(card_picker.cards_tower_lvl3, 5))  do table.insert(allCards, card) end
	for _, card in ipairs(card_picker.repeatItems(card_picker.cards_Veggies, 35)) do table.insert(allCards, card) end
	for _, card in ipairs(card_picker.repeatItems(card_picker.cards_soil, 25))    do table.insert(allCards, card) end
	return allCards

-- Function to randomly select and remove a card
function card_picker.selectAndRemoveCard(allCards)
	if #allCards == 0 then
		return nil  -- No more cards to select

	local index = math.random(#allCards)
	local selectedCard = allCards[index]
	table.remove(allCards, index)  -- Remove the selected card from the list
	return selectedCard

-- Return the module
return card_picker

Then in my gui_script file I assign a random card to each of the 4 slots. Then in the reroll I do the same thing but only 2 cards. I went with a module so I wouldn’t have to rewrite sections of code within the GUI script and it helps keep it cleaner and easier to follow. Also it makes it very easy for me to add new cards and to change the weights in each set as I have it set so the top tier cards are randomly provided less often.

Finally I capture the card they are clicking on by returning the spritename. This will enable me to apply the upgrades via the Attributes module.


Well it’s been about 1 month since an update. Things were a bit tough on me this time. ChatGPT really helped and so did the defold forums.

First I now have a randomized tile map for the garden. Each time it plays the rocks, trees, and obstacles are randomly generated and mirrored on the opposite garden. This was 100% done by ChatGPT. Also I added collisions to the garden obstacles and border so that the polyominos reset if not placed in a legal manner.

Next issue was rotating my polyominos and maintaining the animation upright after rotation. This is where the defold forum helped. I was creating a new animation for each 90 degree turn but that was a lot of animations. So I asked for a better way and @WhiteBoxDev came through with a great solution. make the animation tiles a child of the polyomino game object. Then after rotating 90 degrees do a counter rotation on each of the tiles.

Now I had to fix several things in my code. First thing was I had to learn how to use a collection factory. It wasn’t very difficult, but the big issue is now my object_id doesn’t work since the collection factory returns a table wiht object_ids for each game object in the collection. I finally figured that out and how to get to the obect I wanted. And lesson here was use a generic name for the polyominos and learn LUA tables :slight_smile:

This thread helped me with Collection factory ID issue.

The actual game part is still a ways off and the graphics will be overhauled. But this is where I’m at for the moment.


After a major headache and inconsistencies in the collision objects within defold I changed the way to do this game. Instead of using collisions for tile placement, I’m just manipulating the tile map. This has several advantages for me as I no longer have to align a png to the grid map (but I already had that worked out). But the biggest improvement will be in knowing exactly where each block is on the grid so I can do upgrades easier to the various tiles.

The movement below is actually all in the tilemap. You can see how the movement jumps from square to square.

To make this movement I have a visual_layer on my tilemap and layer1 layer. The visual layer is like a temp layer where the tiles are moved to while dragging. THen if it’s a legal move it writes those tiles to the layer1 layer.


Wow. I’m so glad I switched to using the tilemap to control my polyominos. This is so easy and it’s easier to do upgrades and stuff. It was a bit tricky to have it allow me to spawn two polyominos as the touch was only wanting to recognize the last one spawned. But after a bunch of debugging I fixed it by just doing an original_position_1 and originale_position_2 type variable. And then duplicated the same code for each. It’s not pretty but it works. If I need to ever spawn more than 2 I’ll need to rethink the logic here.

I plan for that to be a “relic” type upgrade. You start by only getting one polyomino to select. But via an upgrade you can start to get two to select and even two to place.

Also I now have an easy way to reset them based on what they are touching. Another relic will allow you to overwrite the polyomino that is under it but at first you won’t be able to replace an already played polyomino.

local forbidden_tile_ids = {2, 3, 4, 5, 6, 10, 11, 12, 13, 14, 17, 29, 30, 40, 44, 45}
local polyomino_tile_ids = {44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59}

function is_position_valid(self)
	for _, pos in ipairs(self.new_positions) do
		local tile_id = tilemap.get_tile("/tilemap#map1", "game_layer", pos.x, pos.y)
		if contains(forbidden_tile_ids, tile_id) then
			return false
		--later I will add a flag to allow this to be skipped if the player had a certain relic that allows it
		if contains(polyomino_tile_ids, tile_id) then
			return false
	return true

The trees and rocks and grass are all forbiden_tile_ids. You can’t place tiles there. Also other polyomino tiles are not allowed to be covered (unless you have a relic…code is coming later). So this works nicely for me.

Also all graphics are just temp graphics to get the base game play down.