I made a game y’all!
Big changes:
- It’s got a menu!
- And a demo mode!
- PLANTS GROW BY THEMSELVES!
- And win/lose screens!
Menu
I set up most of the menu in the Godot UI editor:
One trick that took a while was having some issues with Z-indexing (I’m using that in the PixelEngine
). All I had to do to fix it was put all the UI elements in a CanvasLayer
(Foreground
) and voila.
Then a bit of code to hook things up:
# Main.gd
func _on_play():
get_tree().change_scene("res://scenes/Main.tscn")
func _on_options():
$Foreground/Buttons.visible = false
$Foreground/Options.visible = true
$Foreground/StatusBox.visible = false
func _on_options_done():
$Foreground/Buttons.visible = true
$Foreground/Options.visible = false
$Foreground/StatusBox.visible = true
func _on_quit():
get_tree().quit()
Pretty cool.
Demo
To get demo mode working, I just added a demo
variable to the Main.gd
script and tweaked a few things (I’ll talk about return_to_menu
in a moment):
# Main.gd
func _on_Scores_timeout():
...
if count == 0:
if demo:
reset_sand()
else:
return_to_menu("All the plants died!\nYou lost.\n:(")
elif highest <= TARGET:
if demo:
reset_sand()
else:
return_to_menu("You grew a plant to the top.\nYOU WIN!")
# Tetromino
# Keyboard controls
if get_parent().get_parent().demo:
if randf() < 0.1:
var impulse = IMPULSE * (randf() - 0.5)
var torque = TORQUE * (randf() - 0.5)
for body in bodies:
body.apply_central_impulse(impulse)
body.apply_torque_impulse(torque)
else:
for body in bodies:
if Input.is_action_pressed("ui_right"):
body.apply_central_impulse(IMPULSE)
...
Plant growth
It was taking forever to grow plants with just water to help them grow, so I added the ability for them to grow by themselves:
# PixelEngine.gd
# Try to react with neighboring particles
if current == CELL.plant:
var hot_neighbors = count_neighbors_of(x, y, CELL.fire) + count_neighbors_of(x, y, CELL.lava)
var empty_neighbors = count_neighbors_of(x, y, CELL.empty)
var plant_neighbors = count_neighbors_of(x, y, CELL.plant)
# Fire/lava ignite plants
if randf() < hot_neighbors * BURN_CHANCE_PER_FIRE:
data[x][y] = CELL.fire
updated[x][y] = true
# Plants try to grow
elif empty_neighbors > 0 and plant_neighbors <= PLANT_GROWTH_LIMITER:
for xi in range(x - 1, x + 2):
for yi in range(y - 1, y + 2):
if not in_range(xi, yi) or (xi == x and yi == y):
continue
if data[xi][yi] != CELL.empty:
continue
if randf() < PLANT_GROWTH_PER_EMPTY:
data[xi][yi] = CELL.plant
updated[xi][yi] = true
Win/Lose
Last but not least, I updated the code to include win/lose screens (as seen in the return_to_menu
function above). I did that so that I can go right back to the menu, but also display a message:
# Main.gd
func return_to_menu(message):
var menu = load("res://scenes/Menu.tscn").instance()
menu.set_text(message)
get_tree().get_root().add_child(menu)
queue_free()
I can’t directly use get_tree().change_scene
here, since that doesn’t let me pass along any state, but this works well enough. I may use that for options/difficulty settings before too long.
TODO
Next up: MUSIC!
You need music to really sell a game.
And hey, I already have a menu option for it. :D
If I have the time, after that I will work on:
- Difficulty / options
- Turn on/off spawn types
- Make plants grow easier (allow 1-4 neighbors) or harder (exactly 1)
- Two block mode (I accidently did this in testing, it was neat)
- Wall spawners
- New block types
- Wax
- Acid
- Agent X
- Fireworks
- TNT
- Submit high scores