SphereDefense Construction _ ____ / | / ___| ___ ___ _ __ ___ | | \___ \ / __/ _ \ '_ \ / _ \ | |_ ___) | (_| __/ | | | __/ |_(_) |____/ \___\___|_| |_|\___| - Create a 3D Scene - Node3D Rename Main, save it - Add a WorldEnvironment node create a New Environment for its Environment property set the background to Custom Color pick a light color - Add a camera and make it face the sky. Rotate x 90 degrees - Make the a RigidBody and let it fall on the camera. RigidBody (0, 20, 0)->{MeshInstnace -> Cube(1,1,1), CollisionShape -> Box(.5, .5,.5)} Rename Block - Make the block a separate scene and leave an instance in the main scene. Move Rigid Body to 0 Move instance to 20 TEST - Add a transparent static body paddle above the camera. StaticBody -> {CollisionShape(BoxShape (extends 1, .05, 1)), MeshInstance( size 2, .1, 2)} Color light, alpha ~128 ____ ____ |___ \ | _ \ _ __ ___ _ __ _ __ ___ _ __ __) | | | | | '__/ _ \| '_ \| '_ \ / _ \ '__| / __/ _ | |_| | | | (_) | |_) | |_) | __/ | |_____(_) |____/|_| \___/| .__/| .__/ \___|_| |_| |_| - Create a dropper object which drops blocks at fixed intervals. Spatial -> Children(Node3D), Timer->Script y=20 Drag in Block const BLOCK = preload("res://falling_block.tscn") func _on_Timer_timeout(): call_deferred("start_new_block") func start_new_block(): var new_block = BLOCK.instantiate() add_child(new_block) - Add a random location to the new block. @export var x_range = 5 @export var z_range = 3 var rng = RandomNumberGenerator.new() _ready(): rng.randomize() _timeout var x = rng.randf_range(-x_range, x_range) var z = rng.randf_range(-z_range, z_range) new_block.position = position new_block.position.x += x new_block.position.z += z - Add a random speed/impulse to the block. var impulse = rng.randf_range(0, -100) var torque = Vector3(rng.randf_range(0, 50), rng.randf_range(0, 50), rng.randf_range(0, 50)) new_block.apply_central_impulse(Vector3(0, impulse, 0)) new_block.apply_torque_impulse(torque) _____ ____ _ _ _ |___ / | _ \ __ _ __| | __| | | ___ |_ \ | |_) / _` |/ _` |/ _` | |/ _ \ ___) | | __/ (_| | (_| | (_| | | __/ |____(_) |_| \__,_|\__,_|\__,_|_|\___| - Make the paddle move with the mouse. #GDScript func _input(event): if event is InputEventMouse: var position2D = event.position #get_viewport().get_mouse_position() var dropPlane = Plane(Vector3(0, 1, 0), 3 ) #$Paddle.translation.z) var position3D = dropPlane.intersects_ray( $Camera3D.project_ray_origin(position2D), $Camera3D.project_ray_normal(position2D)) #print(position3D) $Paddle.position = position3D - Add drawn image? Drag to Paddle->MeshInstance: Mesh->Material->Texture _ _ ____ _ _ | || | | __ )| | ___ ___| | _____ | || |_ | _ \| |/ _ \ / __| |/ / __| |__ _| | |_) | | (_) | (__| <\__ \ |_|(_) |____/|_|\___/ \___|_|\_\___/ - Make the blocks bouncy Block-Physics Material Bounce = .5 - Make the block go away after a few seconds. func _on_Timer_timeout(): call_deferred("queue_free") - Make blocks deactivate/change color export var isActive = true @export var offMaterial = Material.new() func _on_Block_body_entered(body): Block => Contacts Report, Monitor if isActive: isActive = false $MeshInstance.set_surface_override_material(0, offMaterial) - Add drawn image? Drag to Paddle->MeshInstance: Mesh->Material->Texture ____ _____ _ | ___| |_ _|_ _ _ __ __ _ ___| |_ |___ \ | |/ _` | '__/ _` |/ _ \ __| ___) | | | (_| | | | (_| | __/ |_ |____(_) |_|\__,_|_| \__, |\___|\__| |___/ - Add collision detector below the paddle. Target (Area3D node) ->CollisionShape3D -> Box Extents (5, .2, 5) Translation -3 func _on_Target_body_entered(body): pass # Replace with function body. __ _ _ ___ / /_ | | | |_ _| | '_ \ | | | || | | (_) | | |_| || | \___(_) \___/|___| - Add UI layer with score. - UI (CanvasLayer) -Label {Control->Theme Overrides->Color} Margin Top 10 Make group blocks for Block if body.is_in_group("blocks") and body.isActive: score -= 5 $UI/Score.text = str(score) Set dropper's timer to .25 - Add count down timer and Timer Label. var seconds = 0 func _on_Clock_timeout(): seconds += 1 $UI/Time.text = str(seconds) Background Image: TextureRect set texture click expand _____ ____ _ _ _______ _ |___ | / ___|| |_ __ _ _ __| |_ / / ____|_ __ __| | / / \___ \| __/ _` | '__| __| / /| _| | '_ \ / _` | / /_ ___) | || (_| | | | |_ / / | |___| | | | (_| | /_/(_) |____/ \__\__,_|_| \__/_/ |_____|_| |_|\__,_| - Add start button var running = false func _on_Start_pressed(): if !running: $UI/StartButton.hide() $Dropper/Timer.start() $Clock.start() running = true; score = 100 seconds = 0 $UI/Score.text = str(score) $UI/Time.text = str(seconds) Turn off auto start on timers - Add game over/start functionality. func _process(delta): if score <= 0: end_game() func end_game(): if running: $UI/StartButton.show() $Dropper/Timer.stop() $Clock.stop() running = false - Game Over Message ___ _ _ _ ( _ ) / \ _ _ __| (_) ___ / _ \ / _ \| | | |/ _` | |/ _ \ | (_) | / ___ \ |_| | (_| | | (_) | \___(_) /_/ \_\__,_|\__,_|_|\___/ - Open QuickTime Player. Record sound. Trim sounds. Save it in Project - Open VLC File -> Convert/Stream Vorbis (OGG) Save in Folder - Select file. Import Tab. Loop off Block: Add AudioStreamPlayer3D call it Sounds Drag .ogg file to Sound->Stream body_entered function: $Sound.play() --------------------------------------------------------------------------------