CS 470 Game Development

Homework Assignment

Juicy Clicker

Applying Tweens, Nodes, and Await from scratch

Due: before next class

Assignment Overview

Homework: Build "Juicy Clicker" from scratch

  • Build the entire project on your own.
  • Complete Challenges 1–3. Challenge 4 is a stretch goal.
  • Submit your project folder as a .zip on the course portal.
  • Hint slides are provided — use them if you get stuck!

The Goal: "Juicy Clicker"

You will build a game from a completely blank project.

  • No starter code.
  • No downloaded assets.
  • No pre-built scenes.

You will take a boring mechanic (clicking a Godot icon) and add layers of "juice" using everything you learned this week.

Project Setup

Start here before tackling any challenge.

  1. Create a brand new Godot project named "Juicy Clicker"
  2. Create a Node2D root, rename it Game
  3. Save the scene as game.tscn
  4. Add a Timer node (Set Autostart = On, Wait Time = 1.0)
  5. Add a Label node for the score
    • Text: "Score: 0"
    • Theme Overrides → Font Size: 48
  6. Attach a script game.gd to the root Game node.

Challenge 1: The Bouncy Spawner

Required

Challenge 1 Requirements

Goal: Spawn a Godot icon every second, but make it pop into existence.

Steps:

  1. Connect the Timer's timeout signal to your game.gd script.
  2. In the function, use Sprite2D.new() to create a node.
  3. Set its texture to the default icon: load("res://icon.svg")
  4. Set its position to a random spot on screen (use randf_range()).
  5. add_child(sprite)
  6. The Juice: Animate scale from (0,0) to (1,1) using a tween with TRANS_BOUNCE and EASE_OUT.

Challenge 1 — Hint

Here's the pattern for the tween:

var tween = create_tween()
tween.tween_property(sprite, "scale", Vector2(1, 1), 0.5)\
    .from(Vector2(0, 0))\
    .set_trans(Tween.TRANS_BOUNCE)\
    .set_ease(Tween.EASE_OUT)

When you succeed: Your screen should slowly fill up with bouncing Godot heads!

Challenge 2: The Parallel Pop

Required

Challenge 2 Requirements

Goal: When clicked, the sprite shouldn't just vanish; it should have a juicy death animation.

Steps:

  1. Detect clicks: We don't have an Area2D! Instead, override _input(event) in game.gd. If it's a mouse click, loop through all children. If a child is a Sprite2D, use event.position.distance_to(child.position) < 64 to detect a hit.
  2. The Juice: When hit, create a tween and use .set_parallel(true) to do three things at once over 0.3 seconds:
    • Scale the sprite up to (2, 2)
    • Fade it out: modulate:a to 0.0
    • Spin it wildly: rotation to TAU * 2
  3. Cleanup: Use await tween.finished then child.queue_free().

Challenge 3: Floating Combat Text

Required

Challenge 3 Requirements

Goal: Give visual feedback exactly where the player clicked.

Steps:

  1. When a sprite is successfully hit, increment a score variable and update your main Label.
  2. Use Label.new() to dynamically spawn a new label exactly at event.position.
  3. Set its text to "+1", change its font size, and add_child(label).
  4. The Juice: Tween the label to float upwards (position.y -= 50) while simultaneously fading out (modulate:a to 0).
  5. Clean up with await and queue_free().

Challenge 4: Tweening the Score

Stretch Goal

Challenge 4 Requirements

Goal: Make the main score counter roll up smoothly instead of instantly snapping.

Steps:

  1. Instead of just adding to score, create a custom variable:
var display_score: int = 0:
    set(value):
        display_score = value
        $Label.text = "Score: %d" % display_score
  1. When you gain a point, don't update the label manually. Instead, tween the variable itself!
  2. tween.tween_property(self, "display_score", actual_score, 0.5)

Submission

Submit your completed project before the next class.

Your submission must include:

  • Your full Godot project folder, zipped
  • Challenges 1, 2, and 3 fully working
  • Challenge 4 is optional (stretch goal)

You will be graded on:

  • Spawned nodes entirely from code (.new())
  • Complex, multi-property parallel animations
  • Math-based collision detection (distance_to)
  • Memory management with await and queue_free()