diff --git a/README.md b/README.md index aa9768a..17b2dbf 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,17 @@ # VCGJ 2025 `Theme: Hold It!` +# Extremely Intense Mathematics +A simple math game where you have to compete against three other little guys. Be the last player standing to win. + +The four players take turn holding what is known as the "rule enforcement device" + +The initial time set on the rule enforcement device before it "enforces the rules" decreases each time a question is answered correctly. + +Each time a question is answered correctly, the device is handed to the next player and the device has the time reset. + +The three other players have their own strengths: + +- Green: Good at subtraction +- Red: Good at multiplication +- Blue: Good at division diff --git a/blender/explosion/explosion.blend b/blender/explosion/explosion.blend index fde77a5..ae3fcc2 100644 Binary files a/blender/explosion/explosion.blend and b/blender/explosion/explosion.blend differ diff --git a/blender/explosion/explosion.blend1 b/blender/explosion/explosion.blend1 index 5ae3516..896efbc 100644 Binary files a/blender/explosion/explosion.blend1 and b/blender/explosion/explosion.blend1 differ diff --git a/blender/explosion/explosion.glb b/blender/explosion/explosion.glb index 7c69274..d30325d 100644 Binary files a/blender/explosion/explosion.glb and b/blender/explosion/explosion.glb differ diff --git a/godot/assets/models/explosion/explosion.glb b/godot/assets/models/explosion/explosion.glb index 7c69274..d30325d 100644 Binary files a/godot/assets/models/explosion/explosion.glb and b/godot/assets/models/explosion/explosion.glb differ diff --git a/godot/main_scenes/game.tscn b/godot/main_scenes/game.tscn index fd123b6..46f6d37 100644 --- a/godot/main_scenes/game.tscn +++ b/godot/main_scenes/game.tscn @@ -72,27 +72,24 @@ script = ExtResource("2_joe7c") unique_name_in_owner = true transform = Transform3D(-0.0475354, -0.0535728, 0.270738, 0.266451, 0.0626881, 0.0591871, -0.0719257, 0.267636, 0.0403304, 0.0257539, -0.692888, -4.06508) -[node name="UI" type="Control" parent="."] -layout_mode = 3 +[node name="UI" type="MarginContainer" parent="."] anchors_preset = 15 anchor_right = 1.0 anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 +mouse_filter = 2 [node name="PanelContainer" type="PanelContainer" parent="UI"] -layout_mode = 0 -offset_right = 40.0 -offset_bottom = 40.0 +layout_mode = 2 theme_override_styles/panel = SubResource("StyleBoxEmpty_sp4xh") [node name="VBoxContainer" type="VBoxContainer" parent="UI/PanelContainer"] layout_mode = 2 -alignment = 2 +alignment = 1 [node name="HBoxContainer" type="HBoxContainer" parent="UI/PanelContainer/VBoxContainer"] layout_mode = 2 -alignment = 2 [node name="QUESTION" type="Label" parent="UI/PanelContainer/VBoxContainer/HBoxContainer"] unique_name_in_owner = true @@ -117,6 +114,20 @@ drag_and_drop_selection_enabled = false flat = true caret_blink = true +[node name="CenterContainer" type="CenterContainer" parent="UI"] +layout_mode = 2 +mouse_filter = 2 + +[node name="WINLOSE" type="Label" parent="UI/CenterContainer"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +theme_override_fonts/font = ExtResource("9_im5ls") +theme_override_font_sizes/font_size = 200 +text = "TEST" +horizontal_alignment = 1 +vertical_alignment = 1 + [node name="SCREAM" type="AudioStreamPlayer3D" parent="."] unique_name_in_owner = true panning_strength = 0.0 diff --git a/godot/main_scenes/menu.tscn b/godot/main_scenes/menu.tscn index 5941033..9e227ae 100644 --- a/godot/main_scenes/menu.tscn +++ b/godot/main_scenes/menu.tscn @@ -37,7 +37,7 @@ layout_mode = 2 layout_mode = 2 theme_override_fonts/font = ExtResource("1_38vls") theme_override_font_sizes/font_size = 120 -text = "Extreme Mathematics" +text = "Extreme Intense Mathematics" [node name="author" type="Label" parent="PanelContainer/HBoxContainer/VBoxContainer"] layout_mode = 2 @@ -53,7 +53,8 @@ theme_override_styles/separator = SubResource("StyleBoxEmpty_38vls") [node name="start_button" type="Button" parent="PanelContainer/HBoxContainer/VBoxContainer"] custom_minimum_size = Vector2(400, 0) layout_mode = 2 -size_flags_horizontal = 4 +size_flags_horizontal = 0 +size_flags_vertical = 4 mouse_default_cursor_shape = 2 theme_override_fonts/font = ExtResource("1_38vls") theme_override_font_sizes/font_size = 96 diff --git a/godot/scripts/ai.gd b/godot/scripts/ai.gd index 60a60e4..b124191 100644 --- a/godot/scripts/ai.gd +++ b/godot/scripts/ai.gd @@ -12,13 +12,13 @@ var currently_executing:bool = false var faster_operand:String = "" var wait_time:int var is_correct:bool +var last_executed_player:int -var clock:int +var clock:int = 0 func _physics_process(_delta: float) -> void: if GLOBALVARS.selected_player != 0: - if not currently_executing: - clock = 0 + if not currently_executing and GLOBALVARS.selected_player != last_executed_player: if GLOBALVARS.selected_player == 1: faster_operand = "-" elif GLOBALVARS.selected_player == 2: @@ -27,20 +27,24 @@ func _physics_process(_delta: float) -> void: faster_operand = "/" if GLOBALVARS.current_operand == faster_operand: - wait_time = randi_range(50,120) + wait_time = randi_range(45,120) is_correct = true if randf() > 0.05 else false else: wait_time = randi_range(60,350) is_correct = true if randf() > 0.15 else false currently_executing = true + last_executed_player = GLOBALVARS.selected_player - elif clock > wait_time: + elif clock > wait_time and currently_executing: if %ANSWER.text == "": - %ANSWER.text = str(GLOBALVARS.current_solution) if is_correct else str(GLOBALVARS.current_solution+randi_range(-2,2)) + %ANSWER.text = str(GLOBALVARS.current_solution) if is_correct else str(GLOBALVARS.current_solution+(1 if randf() > .5 else -1)) elif clock > wait_time + 30: %ANSWER.emit_signal("text_submitted",%ANSWER.text) currently_executing = false + clock = 0 else: clock+=1 else: clock+=1 + else: + last_executed_player = 0 diff --git a/godot/scripts/gamemaster.gd b/godot/scripts/gamemaster.gd index cc47edb..5ebc2fb 100644 --- a/godot/scripts/gamemaster.gd +++ b/godot/scripts/gamemaster.gd @@ -3,6 +3,25 @@ extends Node var cooldown:int = 0 static var SCREAM_ARRAY:Array = [0,1] +func _explode(): + %SCREAM.stream = load("res://assets/sounds/scream_%s.wav" % SCREAM_ARRAY.pick_random()) + %SCREAM.play() + %RULE_ENFORCEMENT.explode() + %QUESTION.visible = false + %ANSWER.visible = false + + cooldown = 180 + if GLOBALVARS.selected_player == 0: + %WINLOSE.visible = true + %WINLOSE.self_modulate = Color(1,0,0) + %WINLOSE.text = ":(" + elif GLOBALVARS.players_remaining == [0]: + %WINLOSE.visible = true + %WINLOSE.self_modulate = Color(0,1,0) + %WINLOSE.text = "You Win! :)" + else: + cooldown = 60 + func _determine_seconds_left() -> float: var difficulty_calc:float = 20-float(GLOBALVARS.difficulty) return difficulty_calc if difficulty_calc >= 3.0 else 3.0 @@ -16,14 +35,13 @@ func _on_answer_text_submitted(_new_text: String) -> void: GLOBALVARS.difficulty+=.5 GLOBALVARS.seconds_left = _determine_seconds_left() _generate_question() + else: - %SCREAM.stream = load("res://assets/sounds/scream_%s.wav" % SCREAM_ARRAY.pick_random()) - %SCREAM.play() - %RULE_ENFORCEMENT.explode() - cooldown = 60 + GLOBALVARS.seconds_left = _determine_seconds_left() GLOBALVARS.rotation_paused = true GLOBALVARS.players_remaining.erase(GLOBALVARS.selected_player) get_node("players/player_%s" % GLOBALVARS.selected_player).queue_free() + _explode() %ANSWER.text = "" @@ -33,8 +51,8 @@ func _generate_question() -> void: # 2 - multiply # 3 - divide - var x:int = randi_range(1,100) - var y:int = randi_range(1,100) + var x:int = randi_range(1,10) + var y:int = randi_range(1,10) var rand_int:int = randi_range(0,3) if rand_int == 0: @@ -44,22 +62,38 @@ func _generate_question() -> void: GLOBALVARS.current_solution = x-y GLOBALVARS.current_operand = "-" elif rand_int == 2: - x = randi_range(0,15) # simplify multiplication - y = randi_range(0,15) + x = randi_range(0,10) # simplify multiplication + y = randi_range(0,10) GLOBALVARS.current_solution = x*y GLOBALVARS.current_operand = "*" elif rand_int == 3: + var fail:int = 0 + var solution:int GLOBALVARS.current_operand = "/" - while x%y != 0: # keep going til the remainder is 0 - x = randi_range(0,100) - y = randi_range(1,100) + + while x%y != 0 and fail < 10000: # keep going til the remainder is 0 + x = randi_range(1,10) + y = randi_range(1,10) @warning_ignore('integer_division') - GLOBALVARS.current_solution = int(x/y) + solution = floor(x/y) + fail+=1 + + GLOBALVARS.current_solution = solution + + if fail >= 10000: # fallback to addition if no division problem can be found in 10000 loops + GLOBALVARS.current_operand = "+" + GLOBALVARS.current_solution = x+y %QUESTION.text = "%s %s %s = " % [x,GLOBALVARS.current_operand,y] + %QUESTION.visible = true + %ANSWER.visible = true func _ready() -> void: + %QUESTION.visible = true + %ANSWER.visible = true + %WINLOSE.visible = false + %WINLOSE.text = "" GLOBALVARS.seconds_left = _determine_seconds_left() _generate_question() @@ -73,13 +107,12 @@ func _physics_process(_delta: float) -> void: %ANSWER.editable = false if GLOBALVARS.seconds_left <= 0: - %RULE_ENFORCEMENT.explode() - cooldown = 60 GLOBALVARS.seconds_left = _determine_seconds_left() GLOBALVARS.rotation_paused = true if GLOBALVARS.selected_player in GLOBALVARS.players_remaining: GLOBALVARS.players_remaining.erase(GLOBALVARS.selected_player) get_node("players/player_%s" % GLOBALVARS.selected_player).queue_free() + _explode() if cooldown <= 0 and GLOBALVARS.rotation_paused: if len(GLOBALVARS.players_remaining) > 1 and 0 in GLOBALVARS.players_remaining: @@ -89,9 +122,6 @@ func _physics_process(_delta: float) -> void: _generate_question() %RULE_ENFORCEMENT.reset_rule_enforcement_device() GLOBALVARS.rotation_paused = false - elif 0 in GLOBALVARS.players_remaining: - get_tree().change_scene_to_file("res://main_scenes/menu.tscn") - else: get_tree().change_scene_to_file("res://main_scenes/menu.tscn") diff --git a/godot/scripts/rule_enforcement_device.gd b/godot/scripts/rule_enforcement_device.gd index 747546a..4c26f3d 100644 --- a/godot/scripts/rule_enforcement_device.gd +++ b/godot/scripts/rule_enforcement_device.gd @@ -2,13 +2,17 @@ extends Node3D static var FUSE_SOUND:AudioStream = preload("res://assets/sounds/fuse.ogg") static var EXPLOSION_SOUND:AudioStream = preload("res://assets/sounds/explode.wav") +static var JITTER_AMOUNT:int = 10 +static var ENFORCEMENT_DEVICE_JITTER_AMOUNT:float = 0.005 var grow_explosion:bool = false +var original_position:Vector3 func reset_rule_enforcement_device() -> void: ''' Start the fuse sound ''' + %SOUNDS.stream = FUSE_SOUND %SOUNDS.volume_db = -10 %SOUNDS.play() @@ -29,12 +33,23 @@ func explode() -> void: %EXPLOSION.visible = true func _ready() -> void: + original_position = position reset_rule_enforcement_device() func _process(_delta: float) -> void: %TIME_LEFT.text = ("%.02f" % GLOBALVARS.seconds_left).replace(".",":") + position = original_position + Vector3( + randf_range(-ENFORCEMENT_DEVICE_JITTER_AMOUNT,ENFORCEMENT_DEVICE_JITTER_AMOUNT), + randf_range(-ENFORCEMENT_DEVICE_JITTER_AMOUNT,ENFORCEMENT_DEVICE_JITTER_AMOUNT), + randf_range(-ENFORCEMENT_DEVICE_JITTER_AMOUNT,ENFORCEMENT_DEVICE_JITTER_AMOUNT) + ) if grow_explosion and %EXPLOSION.scale < Vector3(3,3,3): - %EXPLOSION.scale += Vector3(0.2,0.2,0.2) + %EXPLOSION.scale += Vector3(0.25,0.25,0.25) + %EXPLOSION.rotation_degrees += Vector3( + randf_range(-JITTER_AMOUNT,JITTER_AMOUNT), + randf_range(-JITTER_AMOUNT,JITTER_AMOUNT), + randf_range(-JITTER_AMOUNT,JITTER_AMOUNT) + ) elif grow_explosion: %EXPLOSION.visible = false visible = false