Rewrote the game in C#

Added sounds and music
This commit is contained in:
Mutzi 2024-03-21 11:53:40 +01:00
parent abf8bf23ba
commit afab78db12
Signed by: root
GPG Key ID: 2437494E09F13876
53 changed files with 1117 additions and 741 deletions

View File

@ -0,0 +1,13 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/modules.xml
/contentModel.xml
/.idea.Hellswipers.iml
/projectSettingsUpdater.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@ -0,0 +1 @@
Hellswipers

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

8
Hellswipers.csproj Normal file
View File

@ -0,0 +1,8 @@
<Project Sdk="Godot.NET.Sdk/4.2.1">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework Condition=" '$(GodotTargetPlatform)' == 'android' ">net7.0</TargetFramework>
<TargetFramework Condition=" '$(GodotTargetPlatform)' == 'ios' ">net8.0</TargetFramework>
<EnableDynamicLoading>true</EnableDynamicLoading>
</PropertyGroup>
</Project>

19
Hellswipers.sln Normal file
View File

@ -0,0 +1,19 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hellswipers", "Hellswipers.csproj", "{422EE1A2-8A73-4E79-8DD6-605A9503D575}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
ExportDebug|Any CPU = ExportDebug|Any CPU
ExportRelease|Any CPU = ExportRelease|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{422EE1A2-8A73-4E79-8DD6-605A9503D575}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{422EE1A2-8A73-4E79-8DD6-605A9503D575}.Debug|Any CPU.Build.0 = Debug|Any CPU
{422EE1A2-8A73-4E79-8DD6-605A9503D575}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU
{422EE1A2-8A73-4E79-8DD6-605A9503D575}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU
{422EE1A2-8A73-4E79-8DD6-605A9503D575}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU
{422EE1A2-8A73-4E79-8DD6-605A9503D575}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=Hellswipers/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

15
default_bus_layout.tres Normal file
View File

@ -0,0 +1,15 @@
[gd_resource type="AudioBusLayout" format=3 uid="uid://fdje4ljsp3di"]
[resource]
bus/1/name = &"Music"
bus/1/solo = false
bus/1/mute = false
bus/1/bypass_fx = false
bus/1/volume_db = 0.0
bus/1/send = &"Master"
bus/2/name = &"Sound"
bus/2/solo = false
bus/2/mute = false
bus/2/bypass_fx = false
bus/2/volume_db = 0.0
bus/2/send = &"Master"

View File

@ -60,6 +60,9 @@ Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorActi
ssh_remote_deploy/cleanup_script="Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue
Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue
Remove-Item -Recurse -Force '{temp_dir}'"
dotnet/include_scripts_content=true
dotnet/include_debug_symbols=true
dotnet/embed_build_outputs=false
[preset.1]
@ -100,47 +103,12 @@ unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\"
ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash
kill $(pgrep -x -f \"{temp_dir}/{exe_name} {cmd_args}\")
rm -rf \"{temp_dir}\""
dotnet/include_scripts_content=true
dotnet/include_debug_symbols=true
dotnet/embed_build_outputs=false
[preset.2]
name="Web"
platform="Web"
runnable=false
dedicated_server=false
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path="export/web/hellswipers.html"
encryption_include_filters=""
encryption_exclude_filters=""
encrypt_pck=false
encrypt_directory=false
[preset.2.options]
custom_template/debug=""
custom_template/release=""
variant/extensions_support=false
vram_texture_compression/for_desktop=true
vram_texture_compression/for_mobile=false
html/export_icon=true
html/custom_html_shell=""
html/head_include=""
html/canvas_resize_policy=2
html/focus_canvas_on_start=true
html/experimental_virtual_keyboard=false
progressive_web_app/enabled=false
progressive_web_app/offline_page=""
progressive_web_app/display=1
progressive_web_app/orientation=0
progressive_web_app/icon_144x144=""
progressive_web_app/icon_180x180=""
progressive_web_app/icon_512x512=""
progressive_web_app/background_color=Color(0, 0, 0, 1)
[preset.3]
name="Android"
platform="Android"
runnable=true
@ -155,7 +123,7 @@ encryption_exclude_filters=""
encrypt_pck=false
encrypt_directory=false
[preset.3.options]
[preset.2.options]
custom_template/debug=""
custom_template/release=""
@ -163,9 +131,9 @@ gradle_build/use_gradle_build=false
gradle_build/export_format=0
gradle_build/min_sdk=""
gradle_build/target_sdk=""
architectures/armeabi-v7a=true
architectures/armeabi-v7a=false
architectures/arm64-v8a=true
architectures/x86=true
architectures/x86=false
architectures/x86_64=true
version/code=1
version/name=""
@ -178,8 +146,8 @@ package/exclude_from_recents=false
package/show_in_android_tv=false
package/show_in_app_library=true
package/show_as_launcher_app=false
launcher_icons/main_192x192=""
launcher_icons/adaptive_foreground_432x432=""
launcher_icons/main_192x192="res://icon_android_main.png"
launcher_icons/adaptive_foreground_432x432="res://icon_android_adaptive.png"
launcher_icons/adaptive_background_432x432=""
graphics/opengl_debug=false
xr_features/xr_mode=0
@ -340,3 +308,6 @@ permissions/write_sms=false
permissions/write_social_stream=false
permissions/write_sync_settings=false
permissions/write_user_dictionary=false
dotnet/include_scripts_content=true
dotnet/include_debug_symbols=true
dotnet/embed_build_outputs=false

15
game/arrow.tscn Normal file
View File

@ -0,0 +1,15 @@
[gd_scene load_steps=2 format=3 uid="uid://cjc46cgqe1r20"]
[ext_resource type="Script" path="res://src/Game/Arrow.cs" id="1_fcyti"]
[node name="Outline" type="Polygon2D"]
color = Color(0, 0, 0, 1)
offset = Vector2(-32, -32)
antialiased = true
polygon = PackedVector2Array(0, 20, 0, 44, 20, 44, 20, 64, 32, 64, 64, 32, 32, 0, 20, 0, 20, 20)
script = ExtResource("1_fcyti")
[node name="Inner" type="Polygon2D" parent="."]
offset = Vector2(-32, -32)
antialiased = true
polygon = PackedVector2Array(4, 24, 4, 40, 24, 40, 24, 60, 30, 60, 58, 32, 30, 4, 24, 4, 24, 24)

View File

@ -1,33 +0,0 @@
extends Polygon2D
class_name Arrow
@onready var inner := $Inner
@onready var player := $AnimationPlayer
@export_color_no_alpha var normal_color: Color = Color.WHITE
@export_color_no_alpha var done_color: Color = Color.KHAKI
var dir: Global.DIRS = Global.DIRS.RIGHT :
get:
return dir
set(v):
match v:
Global.DIRS.LEFT: rotation = PI
Global.DIRS.RIGHT: rotation = 0
Global.DIRS.UP: rotation = 3*PI/2
Global.DIRS.DOWN: rotation = PI/2
dir = v
var state: Global.ARROW_STATE = Global.ARROW_STATE.NORMAL :
get:
return state
set(v):
match v:
Global.ARROW_STATE.NORMAL:
if state == Global.ARROW_STATE.DONE:
player.play('done-error')
else:
inner.color = normal_color
Global.ARROW_STATE.DONE: inner.color = done_color
Global.ARROW_STATE.ERROR: player.play('error')
state = v

View File

@ -1,88 +0,0 @@
[gd_scene load_steps=6 format=3 uid="uid://cjc46cgqe1r20"]
[ext_resource type="Script" path="res://game/arrow/arrow.gd" id="1_35aap"]
[sub_resource type="Animation" id="Animation_pyfum"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Inner:color")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Color(1, 1, 1, 1)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath(".:modulate")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Color(1, 1, 1, 1)]
}
[sub_resource type="Animation" id="Animation_qo54c"]
resource_name = "done-error"
length = 0.5
step = 0.05
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Inner:color")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.15, 0.3, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1),
"update": 0,
"values": [Color(0.941176, 0.901961, 0.54902, 1), Color(0.85098, 0.27451, 0.282353, 1), Color(0.85098, 0.27451, 0.282353, 1), Color(1, 1, 1, 1)]
}
[sub_resource type="Animation" id="Animation_1cugm"]
resource_name = "error"
length = 0.5
step = 0.05
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Inner:color")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.15, 0.3, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1),
"update": 0,
"values": [Color(1, 1, 1, 1), Color(0.85098, 0.27451, 0.282353, 1), Color(0.85098, 0.27451, 0.282353, 1), Color(1, 1, 1, 1)]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_hujhs"]
_data = {
"RESET": SubResource("Animation_pyfum"),
"done-error": SubResource("Animation_qo54c"),
"error": SubResource("Animation_1cugm")
}
[node name="Outline" type="Polygon2D"]
color = Color(0, 0, 0, 1)
offset = Vector2(-32, -32)
antialiased = true
polygon = PackedVector2Array(0, 20, 0, 44, 20, 44, 20, 64, 32, 64, 64, 32, 32, 0, 20, 0, 20, 20)
script = ExtResource("1_35aap")
[node name="Inner" type="Polygon2D" parent="."]
offset = Vector2(-32, -32)
antialiased = true
polygon = PackedVector2Array(4, 24, 4, 40, 24, 40, 24, 60, 30, 60, 58, 32, 30, 4, 24, 4, 24, 24)
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
libraries = {
"": SubResource("AnimationLibrary_hujhs")
}

View File

@ -1,111 +0,0 @@
extends Control
signal solved
signal input(correct: bool)
var InputHandler := preload('res://game/input.gd')
const all_data := preload('res://game/gems/data.gd').data
const ArrowScene := preload('res://game/arrow/arrow.tscn')
const total_width := 1920
const space_between_arrows := 8
const img_size := 48
@onready var icons := $Icons
@onready var name_label := $Name
@onready var arrows_container := $Arrows
@onready var error_timer := $ErrorTimer
@onready var player := $AnimationPlayer
var pos := -1
var arrow_count := 0
var raw_dirs: Array[Global.DIRS] = []
var arrows: Array[Arrow] = []
var in_error := true
var next_codes = []
func _on_error_timer_timeout() -> void:
in_error = false
func dir_input(dir: Global.DIRS) -> void:
if in_error:
return
if pos >= len(raw_dirs):
return
if dir == raw_dirs[pos]:
arrows[pos].state = Global.ARROW_STATE.DONE
pos += 1
if pos == arrow_count:
solved.emit()
start_new_round()
input.emit(true)
else:
in_error = true
error_timer.start()
arrows[pos].state = Global.ARROW_STATE.ERROR
for a in arrows:
a.state = Global.ARROW_STATE.NORMAL
pos = 0
input.emit(false)
func start_new_round() -> void:
InputHandler.start = null
var data = next_codes.pop_front()
next_codes.append(all_data[randi() % all_data.size()])
icons.update(data[1], next_codes)
in_error = true
if pos != -1:
raw_dirs.clear()
player.play('round-end')
await player.animation_finished
for n in arrows:
arrows_container.remove_child(n)
n.queue_free()
arrows.clear()
pos = 0
name_label.text = data[0]
raw_dirs.append_array(data[2])
arrow_count = len(data[2])
var total_arrow_width := 64 * arrow_count + space_between_arrows * (arrow_count - 1)
var start_x := (total_width - total_arrow_width) / 2.0
for d in data[2]:
var a: Arrow = ArrowScene.instantiate()
a.set_position(Vector2(start_x, 500))
a.dir = d
arrows.append(a)
arrows_container.add_child(a)
start_x += 64 + space_between_arrows
player.play('round-start')
await player.animation_finished
in_error = false
func _input(event: InputEvent) -> void:
var d = InputHandler._input(event)
if d != null:
dir_input(d)
if event.is_action_released('escape'):
get_tree().change_scene_to_packed(load('res://main_menu/main_menu.tscn'))
func _ready() -> void:
randomize()
for i in range(8):
next_codes.append(all_data[randi() % all_data.size()])
icons.update(null, next_codes)
start_new_round()
solved.connect($StatContainer/Solved._on_solved)
input.connect($StatContainer/Combo._on_input)

View File

@ -1,306 +1,12 @@
[gd_scene load_steps=13 format=3 uid="uid://c4sq21c5gf4tr"]
[gd_scene load_steps=12 format=3 uid="uid://c4sq21c5gf4tr"]
[ext_resource type="Script" path="res://game/game.gd" id="1_dkhe3"]
[ext_resource type="Texture2D" uid="uid://ctuppqhifm5nr" path="res://game/gems/placeholder.png" id="2_1o8ih"]
[ext_resource type="Script" path="res://game/icons.gd" id="2_rgbt2"]
[sub_resource type="GDScript" id="GDScript_sce7k"]
script/source = "extends Label
var count = 0
func _on_solved() -> void:
count += 1
text = str(count)
"
[sub_resource type="GDScript" id="GDScript_ngbu4"]
script/source = "extends Label
var count = 0
func _on_input(correct: bool) -> void:
if correct:
count += 1
else:
count = 0
text = str(count)
"
[sub_resource type="Animation" id="Animation_v1pyg"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Icon:self_modulate")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Color(1, 1, 1, 1)]
}
tracks/1/type = "bezier"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("Icon:position:x")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"handle_modes": PackedInt32Array(0),
"points": PackedFloat32Array(72, -0.25, 0, 0.2, -1),
"times": PackedFloat32Array(0)
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("Icon1:position")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector2(264, 136)]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("Icon2:position")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector2(456, 136)]
}
tracks/4/type = "value"
tracks/4/imported = false
tracks/4/enabled = true
tracks/4/path = NodePath("Icon3:position")
tracks/4/interp = 1
tracks/4/loop_wrap = true
tracks/4/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector2(648, 136)]
}
tracks/5/type = "value"
tracks/5/imported = false
tracks/5/enabled = true
tracks/5/path = NodePath("Icon4:position")
tracks/5/interp = 1
tracks/5/loop_wrap = true
tracks/5/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector2(840, 136)]
}
tracks/6/type = "value"
tracks/6/imported = false
tracks/6/enabled = true
tracks/6/path = NodePath("Icon5:position")
tracks/6/interp = 1
tracks/6/loop_wrap = true
tracks/6/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector2(1032, 136)]
}
tracks/7/type = "value"
tracks/7/imported = false
tracks/7/enabled = true
tracks/7/path = NodePath("Icon6:position")
tracks/7/interp = 1
tracks/7/loop_wrap = true
tracks/7/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector2(1224, 136)]
}
tracks/8/type = "value"
tracks/8/imported = false
tracks/8/enabled = true
tracks/8/path = NodePath("Icon7:position")
tracks/8/interp = 1
tracks/8/loop_wrap = true
tracks/8/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector2(1416, 136)]
}
tracks/9/type = "value"
tracks/9/imported = false
tracks/9/enabled = true
tracks/9/path = NodePath("Icon8:position")
tracks/9/interp = 1
tracks/9/loop_wrap = true
tracks/9/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector2(1608, 136)]
}
tracks/10/type = "value"
tracks/10/imported = false
tracks/10/enabled = true
tracks/10/path = NodePath("Icon8:self_modulate")
tracks/10/interp = 1
tracks/10/loop_wrap = true
tracks/10/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Color(1, 1, 1, 0)]
}
[sub_resource type="Animation" id="Animation_bevbe"]
resource_name = "round-change"
length = 0.4
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Icon:self_modulate")
tracks/0/interp = 1
tracks/0/loop_wrap = false
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.4),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Color(1, 1, 1, 1), Color(1, 1, 1, 0)]
}
tracks/1/type = "bezier"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("Icon:position:x")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"handle_modes": PackedInt32Array(0, 0),
"points": PackedFloat32Array(72, -0.25, 0, 0.2, -1, -520, 0, 0, 0, 0),
"times": PackedFloat32Array(0, 0.4)
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("Icon1:position")
tracks/2/interp = 2
tracks/2/loop_wrap = false
tracks/2/keys = {
"times": PackedFloat32Array(0.0001, 0.4),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector2(264, 136), Vector2(72, 136)]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("Icon2:position")
tracks/3/interp = 2
tracks/3/loop_wrap = false
tracks/3/keys = {
"times": PackedFloat32Array(0, 0.4),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector2(456, 136), Vector2(264, 136)]
}
tracks/4/type = "value"
tracks/4/imported = false
tracks/4/enabled = true
tracks/4/path = NodePath("Icon3:position")
tracks/4/interp = 2
tracks/4/loop_wrap = false
tracks/4/keys = {
"times": PackedFloat32Array(0, 0.4),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector2(648, 136), Vector2(456, 136)]
}
tracks/5/type = "value"
tracks/5/imported = false
tracks/5/enabled = true
tracks/5/path = NodePath("Icon4:position")
tracks/5/interp = 2
tracks/5/loop_wrap = false
tracks/5/keys = {
"times": PackedFloat32Array(0, 0.4),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector2(840, 136), Vector2(648, 136)]
}
tracks/6/type = "value"
tracks/6/imported = false
tracks/6/enabled = true
tracks/6/path = NodePath("Icon5:position")
tracks/6/interp = 2
tracks/6/loop_wrap = false
tracks/6/keys = {
"times": PackedFloat32Array(0, 0.4),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector2(1032, 136), Vector2(840, 136)]
}
tracks/7/type = "value"
tracks/7/imported = false
tracks/7/enabled = true
tracks/7/path = NodePath("Icon6:position")
tracks/7/interp = 2
tracks/7/loop_wrap = false
tracks/7/keys = {
"times": PackedFloat32Array(0, 0.4),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector2(1224, 136), Vector2(1032, 136)]
}
tracks/8/type = "value"
tracks/8/imported = false
tracks/8/enabled = true
tracks/8/path = NodePath("Icon7:position")
tracks/8/interp = 2
tracks/8/loop_wrap = false
tracks/8/keys = {
"times": PackedFloat32Array(0, 0.4),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector2(1416, 136), Vector2(1224, 136)]
}
tracks/9/type = "value"
tracks/9/imported = false
tracks/9/enabled = true
tracks/9/path = NodePath("Icon8:position")
tracks/9/interp = 2
tracks/9/loop_wrap = false
tracks/9/keys = {
"times": PackedFloat32Array(0, 0.4),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector2(1608, 136), Vector2(1416, 136)]
}
tracks/10/type = "value"
tracks/10/imported = false
tracks/10/enabled = true
tracks/10/path = NodePath("Icon8:self_modulate")
tracks/10/interp = 1
tracks/10/loop_wrap = true
tracks/10/keys = {
"times": PackedFloat32Array(0, 0.4),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Color(1, 1, 1, 0), Color(1, 1, 1, 1)]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_bt825"]
_data = {
"RESET": SubResource("Animation_v1pyg"),
"round-change": SubResource("Animation_bevbe")
}
[ext_resource type="Script" path="res://src/Game/Game.cs" id="1_k7a4x"]
[ext_resource type="Script" path="res://src/Game/Stats.cs" id="2_u5dw2"]
[ext_resource type="Script" path="res://src/Game/Icons.cs" id="3_xkfay"]
[ext_resource type="AudioStream" uid="uid://u23ytxxg1iqg" path="res://sounds/swipe_ok.wav" id="4_2w4vj"]
[ext_resource type="AudioStream" uid="uid://b4pdua27sq0f7" path="res://music/_music.tres" id="4_arwoj"]
[ext_resource type="Script" path="res://src/Game/Audio.cs" id="4_xhtam"]
[ext_resource type="AudioStream" uid="uid://c3dpfownsatsb" path="res://sounds/error.wav" id="5_pklm0"]
[sub_resource type="Animation" id="Animation_2hnmi"]
length = 0.001
@ -395,6 +101,7 @@ _data = {
[node name="Gem" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = 20.0
@ -403,13 +110,14 @@ offset_right = -20.0
offset_bottom = -20.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_dkhe3")
script = ExtResource("1_k7a4x")
[node name="StatContainer" type="GridContainer" parent="."]
layout_mode = 0
offset_right = 132.0
offset_bottom = 104.0
columns = 2
script = ExtResource("2_u5dw2")
[node name="SolvedT" type="Label" parent="StatContainer"]
layout_mode = 2
@ -420,7 +128,6 @@ custom_minimum_size = Vector2(50, 0)
layout_mode = 2
text = "0"
horizontal_alignment = 2
script = SubResource("GDScript_sce7k")
[node name="ComboT" type="Label" parent="StatContainer"]
layout_mode = 2
@ -430,62 +137,10 @@ text = "Combo: "
layout_mode = 2
text = "0"
horizontal_alignment = 2
script = SubResource("GDScript_ngbu4")
[node name="Icons" type="Node2D" parent="."]
position = Vector2(448, 128)
script = ExtResource("2_rgbt2")
[node name="AnimationPlayer" type="AnimationPlayer" parent="Icons"]
libraries = {
"": SubResource("AnimationLibrary_bt825")
}
[node name="Icon" type="Sprite2D" parent="Icons"]
position = Vector2(72, 136)
scale = Vector2(3, 3)
texture = ExtResource("2_1o8ih")
[node name="Icon1" type="Sprite2D" parent="Icons"]
position = Vector2(264, 136)
scale = Vector2(3, 3)
texture = ExtResource("2_1o8ih")
[node name="Icon2" type="Sprite2D" parent="Icons"]
position = Vector2(456, 136)
scale = Vector2(3, 3)
texture = ExtResource("2_1o8ih")
[node name="Icon3" type="Sprite2D" parent="Icons"]
position = Vector2(648, 136)
scale = Vector2(3, 3)
texture = ExtResource("2_1o8ih")
[node name="Icon4" type="Sprite2D" parent="Icons"]
position = Vector2(840, 136)
scale = Vector2(3, 3)
texture = ExtResource("2_1o8ih")
[node name="Icon5" type="Sprite2D" parent="Icons"]
position = Vector2(1032, 136)
scale = Vector2(3, 3)
texture = ExtResource("2_1o8ih")
[node name="Icon6" type="Sprite2D" parent="Icons"]
position = Vector2(1224, 136)
scale = Vector2(3, 3)
texture = ExtResource("2_1o8ih")
[node name="Icon7" type="Sprite2D" parent="Icons"]
position = Vector2(1416, 136)
scale = Vector2(3, 3)
texture = ExtResource("2_1o8ih")
[node name="Icon8" type="Sprite2D" parent="Icons"]
self_modulate = Color(1, 1, 1, 0)
position = Vector2(1608, 136)
scale = Vector2(3, 3)
texture = ExtResource("2_1o8ih")
position = Vector2(448, 264)
script = ExtResource("3_xkfay")
[node name="Name" type="Label" parent="."]
layout_mode = 0
@ -496,14 +151,29 @@ offset_bottom = 434.0
text = "Teseoxfugholxcfyhngioldyfhgoiljxcnfohgibncdxflhjnfgdlkh"
[node name="Arrows" type="Node2D" parent="."]
[node name="ErrorTimer" type="Timer" parent="."]
wait_time = 0.5
one_shot = true
position = Vector2(0, 500)
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
libraries = {
"": SubResource("AnimationLibrary_wklcx")
}
[connection signal="timeout" from="ErrorTimer" to="." method="_on_error_timer_timeout"]
[node name="Audio" type="Node" parent="."]
script = ExtResource("4_xhtam")
[node name="MusicPlayer" type="AudioStreamPlayer" parent="Audio"]
stream = ExtResource("4_arwoj")
volume_db = -14.0
autoplay = true
bus = &"Music"
[node name="OkSound" type="AudioStreamPlayer" parent="Audio"]
stream = ExtResource("4_2w4vj")
max_polyphony = 10
bus = &"Sound"
[node name="ErrorSound" type="AudioStreamPlayer" parent="Audio"]
stream = ExtResource("5_pklm0")
volume_db = -8.0
max_polyphony = 10
bus = &"Sound"

View File

@ -1,26 +0,0 @@
extends Node2D
@onready var player := $AnimationPlayer
@onready var main_icon := $Icon
@onready var icons := [
$Icon1,
$Icon2,
$Icon3,
$Icon4,
$Icon5,
$Icon6,
$Icon7,
$Icon8
]
func update(main, queue) -> void:
if main != null:
player.play('round-change')
await player.animation_finished
main_icon.texture = main
for i in range(8):
icons[i].texture = queue[i][1]
player.play('RESET')

View File

@ -1,37 +0,0 @@
extends Object
static var start = null
static func calc_swipe(end):
if start == null:
return null
var delta = end - start
var biggest = max(abs(delta.x), abs(delta.y))
if biggest < 50:
return null
if abs(delta.x) > abs(delta.y):
if delta.x < 0:
return Global.DIRS.LEFT
else:
return Global.DIRS.RIGHT
else:
if delta.y < 0:
return Global.DIRS.UP
else:
return Global.DIRS.DOWN
static func _input(event: InputEvent):
var d = null
if event.is_action_pressed('left_mouse_button'):
start = event.get_position()
if event.is_action_released('left_mouse_button'):
d = calc_swipe(event.get_position())
if event.is_action_released('key_up'):
d = Global.DIRS.UP
if event.is_action_released('key_down'):
d = Global.DIRS.DOWN
if event.is_action_released('key_left'):
d = Global.DIRS.LEFT
if event.is_action_released('key_right'):
d = Global.DIRS.RIGHT
return d

View File

@ -1,4 +0,0 @@
extends Node
enum DIRS {LEFT, RIGHT, UP, DOWN}
enum ARROW_STATE {NORMAL, DONE, ERROR}

BIN
icon_android_adaptive.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://ycsqasqyilmw"
path="res://.godot/imported/icon_android_adaptive.png-a8e85ea9821a16cc4dd84682a0241110.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://icon_android_adaptive.png"
dest_files=["res://.godot/imported/icon_android_adaptive.png-a8e85ea9821a16cc4dd84682a0241110.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

BIN
icon_android_main.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c20x4nkjgf8bc"
path="res://.godot/imported/icon_android_main.png-0753afcb85198f5873b967a43b5a701f.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://icon_android_main.png"
dest_files=["res://.godot/imported/icon_android_main.png-0753afcb85198f5873b967a43b5a701f.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

View File

@ -1,19 +1,11 @@
[gd_scene load_steps=3 format=3 uid="uid://bat14jn36bm8h"]
[gd_scene load_steps=7 format=3 uid="uid://bat14jn36bm8h"]
[sub_resource type="GDScript" id="GDScript_iu3pc"]
script/source = "extends Button
func _pressed() -> void:
get_tree().change_scene_to_packed(load('res://game/game.tscn'))
"
[sub_resource type="GDScript" id="GDScript_7qewh"]
script/source = "extends Button
func _pressed() -> void:
get_tree().root.propagate_notification(NOTIFICATION_WM_CLOSE_REQUEST)
get_tree().quit()
"
[ext_resource type="Script" path="res://src/MainMenu.cs" id="1_av5cs"]
[ext_resource type="Texture2D" uid="uid://douclisbiuxji" path="res://main_menu/sound_on.png" id="2_5sfx4"]
[ext_resource type="Texture2D" uid="uid://c8nr5inhnhliv" path="res://main_menu/sound_off.png" id="3_03fxv"]
[ext_resource type="Texture2D" uid="uid://dv2cueufmljpv" path="res://main_menu/music_on.png" id="4_7h5nd"]
[ext_resource type="Texture2D" uid="uid://srex1nvup3xx" path="res://main_menu/music_off.png" id="5_0dja4"]
[ext_resource type="Script" path="res://src/TextureToggleButton.cs" id="6_bmwx5"]
[node name="Control" type="Control"]
layout_mode = 3
@ -26,6 +18,7 @@ offset_right = -50.0
offset_bottom = -50.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_av5cs")
[node name="StartButton" type="Button" parent="."]
layout_mode = 1
@ -40,20 +33,145 @@ focus_mode = 0
theme_override_font_sizes/font_size = 128
text = " Play Game "
flat = true
script = SubResource("GDScript_iu3pc")
[node name="ExitButton" type="Button" parent="."]
layout_mode = 1
anchors_preset = -1
anchor_left = 0.85
anchor_top = 0.9
anchor_left = 0.8
anchor_top = 0.85
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 0
grow_vertical = 0
focus_mode = 0
theme_override_colors/font_color = Color(0.8, 0.16, 0.16, 1)
theme_override_colors/font_color = Color(0.9, 0.09, 0.09, 1)
theme_override_font_sizes/font_size = 48
text = "Exit"
flat = true
script = SubResource("GDScript_7qewh")
[node name="Settings" type="HBoxContainer" parent="."]
layout_mode = 1
anchors_preset = 2
anchor_top = 1.0
anchor_bottom = 1.0
offset_top = -40.0
offset_right = 40.0
grow_vertical = 0
[node name="SoundToggle" type="BaseButton" parent="Settings"]
_import_path = NodePath("")
unique_name_in_owner = false
process_mode = 0
process_priority = 0
process_physics_priority = 0
process_thread_group = 0
editor_description = ""
visible = true
modulate = Color(1, 1, 1, 1)
self_modulate = Color(0.875, 0.875, 0.875, 1)
show_behind_parent = false
top_level = false
clip_children = 0
light_mask = 1
visibility_layer = 1
z_index = 0
z_as_relative = true
y_sort_enabled = false
texture_filter = 0
texture_repeat = 0
material = null
use_parent_material = false
clip_contents = false
custom_minimum_size = Vector2(0, 0)
layout_direction = 0
layout_mode = 2
size_flags_horizontal = 1
size_flags_vertical = 1
size_flags_stretch_ratio = 1.0
auto_translate = true
localize_numeral_system = true
tooltip_text = ""
focus_neighbor_left = NodePath("")
focus_neighbor_top = NodePath("")
focus_neighbor_right = NodePath("")
focus_neighbor_bottom = NodePath("")
focus_next = NodePath("")
focus_previous = NodePath("")
focus_mode = 2
mouse_filter = 0
mouse_force_pass_scroll_events = true
mouse_default_cursor_shape = 0
theme = null
theme_type_variation = &""
disabled = false
toggle_mode = false
button_pressed = false
action_mode = 1
button_mask = 1
keep_pressed_outside = false
button_group = null
shortcut = null
shortcut_feedback = true
shortcut_in_tooltip = true
script = ExtResource("6_bmwx5")
FalseTexture = ExtResource("2_5sfx4")
TrueTexture = ExtResource("3_03fxv")
[node name="MusicToggle" type="BaseButton" parent="Settings"]
_import_path = NodePath("")
unique_name_in_owner = false
process_mode = 0
process_priority = 0
process_physics_priority = 0
process_thread_group = 0
editor_description = ""
visible = true
modulate = Color(1, 1, 1, 1)
self_modulate = Color(0.875, 0.875, 0.875, 1)
show_behind_parent = false
top_level = false
clip_children = 0
light_mask = 1
visibility_layer = 1
z_index = 0
z_as_relative = true
y_sort_enabled = false
texture_filter = 0
texture_repeat = 0
material = null
use_parent_material = false
clip_contents = false
custom_minimum_size = Vector2(0, 0)
layout_direction = 0
layout_mode = 2
size_flags_horizontal = 1
size_flags_vertical = 1
size_flags_stretch_ratio = 1.0
auto_translate = true
localize_numeral_system = true
tooltip_text = ""
focus_neighbor_left = NodePath("")
focus_neighbor_top = NodePath("")
focus_neighbor_right = NodePath("")
focus_neighbor_bottom = NodePath("")
focus_next = NodePath("")
focus_previous = NodePath("")
focus_mode = 2
mouse_filter = 0
mouse_force_pass_scroll_events = true
mouse_default_cursor_shape = 0
theme = null
theme_type_variation = &""
disabled = false
toggle_mode = false
button_pressed = false
action_mode = 1
button_mask = 1
keep_pressed_outside = false
button_group = null
shortcut = null
shortcut_feedback = true
shortcut_in_tooltip = true
script = ExtResource("6_bmwx5")
FalseTexture = ExtResource("4_7h5nd")
TrueTexture = ExtResource("5_0dja4")

BIN
main_menu/music_off.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 908 B

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://srex1nvup3xx"
path="res://.godot/imported/music_off.png-df269b29cf7b9b15af5566f9b7842386.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://main_menu/music_off.png"
dest_files=["res://.godot/imported/music_off.png-df269b29cf7b9b15af5566f9b7842386.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

BIN
main_menu/music_on.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 585 B

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dv2cueufmljpv"
path="res://.godot/imported/music_on.png-85eca01b59a27fc90974c5dc1cc6989a.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://main_menu/music_on.png"
dest_files=["res://.godot/imported/music_on.png-85eca01b59a27fc90974c5dc1cc6989a.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

BIN
main_menu/sound_off.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c8nr5inhnhliv"
path="res://.godot/imported/sound_off.png-14145494ed899d3cf624b0f44e93c9dc.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://main_menu/sound_off.png"
dest_files=["res://.godot/imported/sound_off.png-14145494ed899d3cf624b0f44e93c9dc.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

BIN
main_menu/sound_on.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://douclisbiuxji"
path="res://.godot/imported/sound_on.png-937b2ce2011fd25a7d8d80a1b1918374.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://main_menu/sound_on.png"
dest_files=["res://.godot/imported/sound_on.png-937b2ce2011fd25a7d8d80a1b1918374.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

BIN
music/Retro Arcade.mp3 Normal file

Binary file not shown.

View File

@ -0,0 +1,19 @@
[remap]
importer="mp3"
type="AudioStreamMP3"
uid="uid://c70my28fdjy2a"
path="res://.godot/imported/Retro Arcade.mp3-c2fb5aecbd1645c267f1f4010361e78c.mp3str"
[deps]
source_file="res://music/Retro Arcade.mp3"
dest_files=["res://.godot/imported/Retro Arcade.mp3-c2fb5aecbd1645c267f1f4010361e78c.mp3str"]
[params]
loop=false
loop_offset=0
bpm=0
beat_count=0
bar_beats=4

8
music/_music.tres Normal file
View File

@ -0,0 +1,8 @@
[gd_resource type="AudioStreamRandomizer" load_steps=2 format=3 uid="uid://b4pdua27sq0f7"]
[ext_resource type="AudioStream" uid="uid://c70my28fdjy2a" path="res://music/Retro Arcade.mp3" id="1_jonx2"]
[resource]
streams_count = 1
stream_0/stream = ExtResource("1_jonx2")
stream_0/weight = 1.0

1
music/sources.txt Normal file
View File

@ -0,0 +1 @@
Retro Arcade: https://soundcloud.com/beat-mekanik/retro-arcade

View File

Before

Width:  |  Height:  |  Size: 639 B

After

Width:  |  Height:  |  Size: 639 B

View File

@ -3,15 +3,15 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://ctuppqhifm5nr"
path="res://.godot/imported/placeholder.png-7df2040f50328a788de3559fa4c98f44.ctex"
path="res://.godot/imported/placeholder.png-ef21141e6f7fef7ccb4b638348400c3b.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://game/gems/placeholder.png"
dest_files=["res://.godot/imported/placeholder.png-7df2040f50328a788de3559fa4c98f44.ctex"]
source_file="res://placeholder.png"
dest_files=["res://.godot/imported/placeholder.png-ef21141e6f7fef7ccb4b638348400c3b.ctex"]
[params]

View File

@ -8,21 +8,22 @@
config_version=5
[CustomResourceRegister]
ScriptsFolder="res://src/"
ClassPrefix=""
[application]
config/name="Hellswipers"
config/version="1.1.0"
run/main_scene="res://main_menu/main_menu.tscn"
config/features=PackedStringArray("4.2", "Mobile")
config/features=PackedStringArray("4.2", "C#", "Mobile")
boot_splash/show_image=false
boot_splash/fullsize=false
boot_splash/use_filter=false
config/icon="res://icon.svg"
[autoload]
Global="*res://global.gd"
[display]
window/size/viewport_width=1920
@ -31,10 +32,13 @@ window/size/mode=3
window/size/borderless=true
window/stretch/mode="canvas_items"
[editor]
[dotnet]
version_control/plugin_name="GitPlugin"
version_control/autoload_on_startup=true
project/assembly_name="Hellswipers"
[editor_plugins]
enabled=PackedStringArray()
[file_customization]
@ -49,11 +53,6 @@ theme/custom_font="res://TitilliumWeb-Bold.ttf"
[input]
left_mouse_button={
"deadzone": 0.5,
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":1,"canceled":false,"pressed":false,"double_click":false,"script":null)
]
}
key_up={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"echo":false,"script":null)

BIN
sounds/error.wav Normal file

Binary file not shown.

24
sounds/error.wav.import Normal file
View File

@ -0,0 +1,24 @@
[remap]
importer="wav"
type="AudioStreamWAV"
uid="uid://c3dpfownsatsb"
path="res://.godot/imported/error.wav-96ee995c279b7ea423bbc5828e047ff6.sample"
[deps]
source_file="res://sounds/error.wav"
dest_files=["res://.godot/imported/error.wav-96ee995c279b7ea423bbc5828e047ff6.sample"]
[params]
force/8_bit=false
force/mono=false
force/max_rate=false
force/max_rate_hz=44100
edit/trim=false
edit/normalize=false
edit/loop_mode=0
edit/loop_begin=0
edit/loop_end=-1
compress/mode=0

BIN
sounds/swipe_ok.wav Normal file

Binary file not shown.

View File

@ -0,0 +1,24 @@
[remap]
importer="wav"
type="AudioStreamWAV"
uid="uid://u23ytxxg1iqg"
path="res://.godot/imported/swipe_ok.wav-db18ef3c501416924852d6b1692ece79.sample"
[deps]
source_file="res://sounds/swipe_ok.wav"
dest_files=["res://.godot/imported/swipe_ok.wav-db18ef3c501416924852d6b1692ece79.sample"]
[params]
force/8_bit=false
force/mono=false
force/max_rate=false
force/max_rate_hz=44100
edit/trim=false
edit/normalize=false
edit/loop_mode=0
edit/loop_begin=0
edit/loop_end=-1
compress/mode=0

44
src/Game/Arrow.cs Normal file
View File

@ -0,0 +1,44 @@
using Godot;
using System;
namespace Hellswipers.Game;
public partial class Arrow : Polygon2D {
public enum Dirs { Right, Down, Left, Up }
private static readonly Color NormalColor = Colors.White;
private static readonly Color DoneColor = Colors.Khaki;
private static readonly Color ErrorColor = Color.Color8(217, 70, 72);
private Polygon2D _inner;
private bool _done = false;
public Dirs CurrentDir { private set; get; }
public override void _Ready() {
_inner = GetNode<Polygon2D>("Inner");
}
public void SetDir(Dirs dir) {
CurrentDir = dir;
Rotation = dir switch {
Dirs.Right => 0,
Dirs.Down => (float)(Math.PI / 2),
Dirs.Left => (float)Math.PI,
Dirs.Up => (float)(Math.PI * 3 / 2),
_ => Rotation
};
}
public void Done() {
_done = true;
_inner.Color = DoneColor;
}
public void Error() {
var tween = CreateTween();
tween.TweenProperty(_inner, "color", ErrorColor, 0.15);
tween.TweenInterval(0.15);
tween.TweenProperty(_inner, "color", NormalColor, 0.2);
_done = false;
}
}

16
src/Game/Audio.cs Normal file
View File

@ -0,0 +1,16 @@
using Godot;
namespace Hellswipers.Game;
public partial class Audio : Node {
private AudioStreamPlayer _okPlayer;
private AudioStreamPlayer _errPlayer;
public void Ok() => _okPlayer.Play();
public void Err() => _errPlayer.Play();
public override void _Ready() {
_okPlayer = GetNode<AudioStreamPlayer>("OkSound");
_errPlayer = GetNode<AudioStreamPlayer>("ErrorSound");
}
}

149
src/Game/Game.cs Normal file
View File

@ -0,0 +1,149 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Godot;
namespace Hellswipers.Game;
public partial class Game : Control {
private const int TotalWidth = 1920;
private const int SpaceBetweenArrows = 8;
private const long ErrorLengthMs = 400;
private PackedScene _arrowScene;
private AnimationPlayer _player;
private Node2D _arrowsNode;
private Label _nameLabel;
private Icons _icons;
private readonly Gem[] _gems = Gem.LoadGems();
private readonly Random _rand = new();
private readonly Stopwatch _errorWatch = new();
private readonly Queue<Gem> _nextGems = new();
private readonly List<Arrow> _arrows = new();
private Gem _current;
private bool _disabled = false;
private int _pos = -1;
public delegate void VoidEventHandler();
public event VoidEventHandler SwipeOk;
public event VoidEventHandler SwipeErr;
public event VoidEventHandler Solved;
private Gem RandomGem() => _gems[_rand.Next(_gems.Length)];
private async void StartNewRound() {
var gem = RandomGem();
_icons.Update(gem);
_nextGems.Enqueue(gem);
_current = _nextGems.Dequeue();
_disabled = true;
var tween = CreateTween();
tween.SetParallel();
if (_pos != -1) {
_arrows.ForEach(v => {
var newPos = v.CurrentDir switch {
Arrow.Dirs.Right => new Vector2(100, 0),
Arrow.Dirs.Down => new Vector2(0, 100),
Arrow.Dirs.Left => new Vector2(-100, 0),
Arrow.Dirs.Up => new Vector2(0, -100),
_ => new Vector2(0, 0)
};
tween.TweenProperty(v, "position", v.Position + newPos, 0.2);
});
_player.Play("round-end");
await ToSignal(_player, AnimationMixer.SignalName.AnimationFinished);
_arrows.ForEach(v => {
_arrowsNode.RemoveChild(v);
v.QueueFree();
});
_arrows.Clear();
tween = CreateTween();
tween.SetParallel();
}
_pos = 0;
_nameLabel.Text = _current.Name;
var arrowCount = _current.Dirs.Length;
var totalArrowWidth = 64 * arrowCount + SpaceBetweenArrows * (arrowCount - 1);
var xPos = (TotalWidth - totalArrowWidth) / 2;
foreach (var dir in _current.Dirs) {
var arrow = _arrowScene.Instantiate<Arrow>();
var startPos = dir switch {
Arrow.Dirs.Right => new Vector2(-100, 0),
Arrow.Dirs.Down => new Vector2(0, -100),
Arrow.Dirs.Left => new Vector2(100, 0),
Arrow.Dirs.Up => new Vector2(0, 100),
_ => new Vector2(0, 0)
};
startPos.X += xPos;
arrow.Position = startPos;
tween.TweenProperty(arrow, "position", new Vector2(xPos, 0), 0.2);
arrow.SetDir(dir);
_arrows.Add(arrow);
_arrowsNode.AddChild(arrow);
xPos += 64 + SpaceBetweenArrows;
}
_player.Play("round-start");
await ToSignal(_player, AnimationMixer.SignalName.AnimationFinished);
_disabled = false;
}
private void HandleInput(Arrow.Dirs dir) {
if (_disabled) {
if (_errorWatch.IsRunning && _errorWatch.ElapsedMilliseconds >= ErrorLengthMs) {
_disabled = false;
_errorWatch.Stop();
} else return;
}
if (_pos >= _current.Dirs.Length) return;
if (dir == _current.Dirs[_pos]) {
_arrows[_pos].Done();
_pos++;
SwipeOk!.Invoke();
if (_pos == _current.Dirs.Length) {
Solved!.Invoke();
StartNewRound();
}
} else {
_disabled = true;
SwipeErr!.Invoke();
_errorWatch.Start();
_arrows.ForEach(v => v.Error());
_pos = 0;
}
}
public override void _Ready() {
_player = GetNode<AnimationPlayer>("AnimationPlayer");
_arrowsNode = GetNode<Node2D>("Arrows");
_nameLabel = GetNode<Label>("Name");
_icons = GetNode<Icons>("Icons");
var stats = GetNode<Stats>("StatContainer");
SwipeOk += () => stats.Combo++;
SwipeErr += () => stats.Combo = 0;
Solved += () => stats.Solved++;
var audio = GetNode<Audio>("Audio");
SwipeOk += audio.Ok;
SwipeErr += audio.Err;
_arrowScene = ResourceLoader.Load<PackedScene>("res://game/arrow.tscn");
for (int i = 0; i < 7; ++i)
_nextGems.Enqueue(RandomGem());
_icons.Init(_nextGems.ToArray());
StartNewRound();
}
}

88
src/Game/GemData.cs Normal file
View File

@ -0,0 +1,88 @@
using System.Linq;
using Godot;
namespace Hellswipers.Game;
public record struct Gem {
public readonly Texture2D Texture;
public readonly string Name;
public readonly Arrow.Dirs[] Dirs;
public Gem(string Name, string textureName, Arrow.Dirs[] Dirs) {
this.Name = Name;
this.Dirs = Dirs;
Texture = ResourceLoader.Load<Texture2D>(textureName);
}
public Variant this[int i] {
get {
switch (i) {
case 0:
return Name;
case 1:
return Texture;
case 2:
return Dirs.Select(v => (int)v).ToArray();
}
return 0;
}
}
public static Gem[] LoadGems() => new Gem[] {
new ("LIFT-850 Jump Pack", "res://game/gems/LIFT-850icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Up,Arrow.Dirs.Down,Arrow.Dirs.Up}),
new ("B-1 Supply Pack", "res://game/gems/B-1icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Up,Arrow.Dirs.Down}),
new ("AX/LAS-5 \"Guard Dog\" Rover", "res://game/gems/AX-LAS-5icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Left,Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Right}),
new ("SH-20 Ballistic Shield Backpack", "res://game/gems/SH-20icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Down,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Left}),
new ("SH-32 Shield Generator Pack", "res://game/gems/SH-32icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Left,Arrow.Dirs.Right,Arrow.Dirs.Left,Arrow.Dirs.Right}),
new ("AX/AR-23 \"Guard Dog\"", "res://game/gems/AX-AR-23icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Left,Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Down}),
new ("MG-43 Machine Gun", "res://game/gems/MG-43icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Right}),
new ("APW-1 Anti-Materiel Rifle", "res://game/gems/APW-1icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Right,Arrow.Dirs.Up,Arrow.Dirs.Down}),
new ("M-105 Stalwart", "res://game/gems/M-105icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Up,Arrow.Dirs.Left}),
new ("EAT-17 Expendable Anti-tank", "res://game/gems/EAT-17icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Up,Arrow.Dirs.Right}),
new ("GR-8 Recoilless Rifle", "res://game/gems/GR-8icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Right,Arrow.Dirs.Right,Arrow.Dirs.Left}),
new ("FLAM-40 Flamethrower", "res://game/gems/FLAM-40icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Up,Arrow.Dirs.Down,Arrow.Dirs.Up}),
new ("AC-8 Autocannon", "res://game/gems/AC-8icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Up,Arrow.Dirs.Right}),
new ("RS-422 Railgun", "res://game/gems/RS-422icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Left,Arrow.Dirs.Right}),
new ("FAF-14 SPEAR Launcher", "res://game/gems/FAF-14icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Down,Arrow.Dirs.Down}),
new ("GL-21 Grenade Launcher", "res://game/gems/GL-21icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Up,Arrow.Dirs.Left,Arrow.Dirs.Down}),
new ("LAS-98 Laser Cannon", "res://game/gems/LAS-98icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Left}),
new ("ARC-3 Arc Thrower", "res://game/gems/ARC-3icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Left,Arrow.Dirs.Left}),
new ("Reinforce", "res://game/gems/Reinforceicon.png", new [] {Arrow.Dirs.Up,Arrow.Dirs.Down,Arrow.Dirs.Right,Arrow.Dirs.Left,Arrow.Dirs.Up}),
new ("SOS Beacon", "res://game/gems/SOSicon.png", new [] {Arrow.Dirs.Up,Arrow.Dirs.Down,Arrow.Dirs.Right,Arrow.Dirs.Up}),
new ("Resupply", "res://game/gems/ResupplyIcon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Right}),
new ("NUX-223 Hellbomb", "res://game/gems/Strat_NUX-223_Hellbomb_mk1.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Left,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Up}),
new ("SSSD Delivery", "res://game/gems/DeliverSSSDicon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Down,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Up}),
new ("Seismic Probe", "res://game/gems/Seismic_probe_icon.png", new [] {Arrow.Dirs.Up,Arrow.Dirs.Up,Arrow.Dirs.Left,Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Down}),
new ("Upload Data", "res://game/gems/DeliverSSSDicon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Up,Arrow.Dirs.Up}),
new ("Eagle Rearm", "res://game/gems/HD2_Eagle_Rearm_Icon.jpg", new [] {Arrow.Dirs.Up,Arrow.Dirs.Up,Arrow.Dirs.Left,Arrow.Dirs.Up,Arrow.Dirs.Right}),
new ("E/MG-101 HMG Emplacement", "res://game/gems/HMGTurreticon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Left,Arrow.Dirs.Right,Arrow.Dirs.Right,Arrow.Dirs.Left}),
new ("FX-12 Shield Generator Relay", "res://game/gems/Shieldrelayicon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Right,Arrow.Dirs.Left,Arrow.Dirs.Right}),
new ("A/ARC-3 Tesla Tower", "res://game/gems/Teslaicon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Up,Arrow.Dirs.Left,Arrow.Dirs.Right}),
new ("MD-6 Anti-Personnel Minefield", "res://game/gems/Minefieldicon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Up,Arrow.Dirs.Right}),
new ("MD-I4 Incendiary Mines", "res://game/gems/Fireminefieldicon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Left,Arrow.Dirs.Down}),
new ("A/MG-43 Machine Gun Sentry", "res://game/gems/MGsentryicon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Right,Arrow.Dirs.Up}),
new ("A/G-16 Gatling Sentry", "res://game/gems/Gatlingsentryicon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Left}),
new ("A/M-12 Mortar Sentry", "res://game/gems/Mortarsentryicon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Right,Arrow.Dirs.Down}),
new ("A/AC-8 Autocannon Sentry", "res://game/gems/Autocannoasentryicon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Up,Arrow.Dirs.Left,Arrow.Dirs.Up}),
new ("A/MLS-4X Rocket Sentry", "res://game/gems/Missilesentryicon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Right,Arrow.Dirs.Left}),
new ("A/M-23 EMS Mortar Sentry", "res://game/gems/EMSmortaricon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Right}),
new ("Orbital Gatling Barrage", "res://game/gems/OrbitalGatlingicon.png", new [] {Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Up,Arrow.Dirs.Up}),
new ("Orbital Airburst Strike", "res://game/gems/OrbitalAirbursticon.png", new [] {Arrow.Dirs.Right,Arrow.Dirs.Right,Arrow.Dirs.Right}),
new ("Orbital 120MM HE Barrage", "res://game/gems/Orbital120icon.png", new [] {Arrow.Dirs.Right,Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Right,Arrow.Dirs.Down}),
new ("Orbital 380MM HE Barrage", "res://game/gems/Orbital380icon.png", new [] {Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Up,Arrow.Dirs.Left,Arrow.Dirs.Down,Arrow.Dirs.Down}),
new ("Orbital Walking Barrage", "res://game/gems/OrbitalWalkingicon.png", new [] {Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Right,Arrow.Dirs.Down}),
new ("Orbital Laser", "res://game/gems/OrbitalLasericon.png", new [] {Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Down}),
new ("Orbital Railcannon Strike", "res://game/gems/OrbitalRailcannonicon.png", new [] {Arrow.Dirs.Right,Arrow.Dirs.Up,Arrow.Dirs.Down,Arrow.Dirs.Down,Arrow.Dirs.Right}),
new ("Orbital Precision Strike", "res://game/gems/OrbitalPrecisionicon.png", new [] {Arrow.Dirs.Right,Arrow.Dirs.Right,Arrow.Dirs.Up}),
new ("Orbital Gas Strike", "res://game/gems/OrbitalGasicon.png", new [] {Arrow.Dirs.Right,Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Right}),
new ("Orbital EMS Strike", "res://game/gems/OrbitalEMSicon.png", new [] {Arrow.Dirs.Right,Arrow.Dirs.Right,Arrow.Dirs.Left,Arrow.Dirs.Down}),
new ("Orbital Smoke Strike", "res://game/gems/OrbitalSmokeicon.png", new [] {Arrow.Dirs.Right,Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Up}),
new ("Eagle Strafing Run", "res://game/gems/EagleStrafingicon.png", new [] {Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Right}),
new ("Eagle Airstrike", "res://game/gems/EagleAirstrikeicon.png", new [] {Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Right}),
new ("Eagle Cluster Bomb", "res://game/gems/EagleClusterbombicon.png", new [] {Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Down,Arrow.Dirs.Right}),
new ("Eagle Napalm Airstrike", "res://game/gems/EagleNapalmicon.png", new [] {Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Up}),
new ("Eagle Smoke Strike", "res://game/gems/EagleSmokeicon.png", new [] {Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Up,Arrow.Dirs.Down}),
new ("Eagle 110MM Rocket Pods", "res://game/gems/EagleRocketpodicon.png", new [] {Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Up,Arrow.Dirs.Left}),
new ("Eagle 500kg Bomb", "res://game/gems/Eagle500icon.png", new [] {Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Down,Arrow.Dirs.Down})
};
}

56
src/Game/Icons.cs Normal file
View File

@ -0,0 +1,56 @@
using System.Collections.Generic;
using Godot;
namespace Hellswipers.Game;
public partial class Icons : Node2D {
private const int IconSize = 144;
private const int SpaceBetween = 48;
private const int TotalIconSize = IconSize + SpaceBetween;
private const double AnimationLength = 0.4;
private static readonly Vector2 IconScale = new(3, 3);
private readonly Queue<Sprite2D> _icons = new();
private Sprite2D CreateIcon(Texture2D tex) {
var icon = new Sprite2D();
icon.Texture = tex;
icon.Scale = IconScale;
AddChild(icon);
_icons.Enqueue(icon);
return icon;
}
public void Init(Gem[] nextGems) {
CreateIcon(null);
var pos = TotalIconSize;
foreach (var gem in nextGems) {
CreateIcon(gem.Texture).Position = new(pos, 0);
pos += TotalIconSize;
}
}
public void Update(Gem gem) {
var tween = CreateTween();
tween.SetParallel();
tween.SetTrans(Tween.TransitionType.Cubic);
tween.SetEase(Tween.EaseType.InOut);
var oldIcon = _icons.Dequeue();
tween.TweenProperty(oldIcon, "position:x", -Position.X - IconSize, AnimationLength);
tween.TweenProperty(oldIcon, "self_modulate", new Color(1, 1, 1, 0), AnimationLength);
var newIcon = CreateIcon(gem.Texture);
newIcon.Position = new(_icons.Count * TotalIconSize, 0);
newIcon.SelfModulate = new(1, 1, 1, 0);
tween.TweenProperty(newIcon, "self_modulate", new Color(1, 1, 1, 1), AnimationLength);
foreach (var icon in _icons)
tween.TweenProperty(icon, "position:x", icon.Position.X - TotalIconSize, AnimationLength);
tween.Finished += () => {
RemoveChild(oldIcon);
oldIcon.QueueFree();
};
}
}

46
src/Game/Input.cs Normal file
View File

@ -0,0 +1,46 @@
using System;
using Godot;
namespace Hellswipers.Game;
public partial class Game {
private Vector2? _swipeStart;
private void CalcSwipe(Vector2 end) {
if (!_swipeStart.HasValue)
return;
var delta = end - _swipeStart.Value;
_swipeStart = null;
var deltaAbs = delta.Abs();
var biggest = Math.Max(deltaAbs.X, deltaAbs.Y);
if (biggest < 50)
return;
HandleInput(deltaAbs.X > deltaAbs.Y
? (delta.X > 0 ? Arrow.Dirs.Right : Arrow.Dirs.Left)
: (delta.Y > 0 ? Arrow.Dirs.Down : Arrow.Dirs.Up)
);
}
public override void _UnhandledInput(InputEvent ev) {
if (ev is InputEventMouseButton evm) {
if (ev.IsPressed())
_swipeStart = evm.Position;
else
CalcSwipe(evm.Position);
} else {
if (ev.IsActionPressed("key_up"))
HandleInput(Arrow.Dirs.Up);
else if (ev.IsActionPressed("key_down"))
HandleInput(Arrow.Dirs.Down);
else if (ev.IsActionPressed("key_left"))
HandleInput(Arrow.Dirs.Left);
else if (ev.IsActionPressed("key_right"))
HandleInput(Arrow.Dirs.Right);
else if (ev.IsActionPressed("escape"))
GetTree().ChangeSceneToPacked(ResourceLoader.Load<PackedScene>("res://main_menu/main_menu.tscn"));
}
}
}

33
src/Game/Stats.cs Normal file
View File

@ -0,0 +1,33 @@
using Godot;
namespace Hellswipers.Game;
public partial class Stats : Node {
private Label _comboLabel;
private Label _solvedLabel;
private int _combo = 0;
private int _solved = 0;
public int Combo {
get => _combo;
set {
_combo = value;
_comboLabel.Text = _combo.ToString();
}
}
public int Solved {
get => _solved;
set {
_solved = value;
_solvedLabel.Text = _solved.ToString();
}
}
public override void _Ready() {
_comboLabel = GetNode<Label>("Combo");
_solvedLabel = GetNode<Label>("Solved");
}
}

26
src/MainMenu.cs Normal file
View File

@ -0,0 +1,26 @@
using Godot;
namespace Hellswipers;
public partial class MainMenu : Control {
public override void _Ready() {
Settings.Init();
var sb = GetNode<TextureToggleButton>("Settings/SoundToggle");
sb.State = Settings.SoundMute;
sb.StateChanged = v => Settings.SoundMute = v;
var mb = GetNode<TextureToggleButton>("Settings/MusicToggle");
mb.State = Settings.MusicMute;
mb.StateChanged = v => Settings.MusicMute = v;
GetNode<Button>("StartButton").Pressed +=
() => GetTree().ChangeSceneToPacked(ResourceLoader.Load<PackedScene>("res://game/game.tscn"));
GetNode<Button>("ExitButton").Pressed += () => {
var tree = GetTree();
tree.Root.PropagateNotification((int)NotificationWMCloseRequest);
tree.Quit();
};
}
}

26
src/Settings.cs Normal file
View File

@ -0,0 +1,26 @@
using Godot;
namespace Hellswipers;
public static class Settings {
private static bool _initDone;
private static int _soundBus, _musicBus;
public static bool SoundMute {
get => AudioServer.IsBusMute(_soundBus);
set => AudioServer.SetBusMute(_soundBus, value);
}
public static bool MusicMute {
get => AudioServer.IsBusMute(_musicBus);
set => AudioServer.SetBusMute(_musicBus, value);
}
public static void Init() {
if (_initDone) return;
_initDone = true;
_soundBus = AudioServer.GetBusIndex("Sound");
_musicBus = AudioServer.GetBusIndex("Music");
}
}

View File

@ -0,0 +1,54 @@
using System;
using Godot;
namespace Hellswipers;
[Tool]
[GlobalClass]
public partial class TextureToggleButton : BaseButton {
public Action<bool> StateChanged = null;
[Export] public Texture2D FalseTexture;
[Export] public Texture2D TrueTexture;
[Export]
public bool State {
get => _state;
set {
_state = value;
StateChanged?.Invoke(value);
QueueRedraw();
}
}
private bool _state;
private Color _baseColor;
private Color _hoverColor;
private Color _pressColor;
public override Vector2 _GetMinimumSize() => new(
Math.Max(FalseTexture?.GetWidth() ?? 0, TrueTexture?.GetWidth() ?? 0),
Math.Max(FalseTexture?.GetHeight() ?? 0, TrueTexture?.GetHeight() ?? 0)
);
public override void _Pressed() => State = !State;
public override void _Draw() {
SelfModulate = GetDrawMode() switch {
DrawMode.Normal => _baseColor,
DrawMode.Disabled => _baseColor,
DrawMode.Hover => _hoverColor,
DrawMode.Pressed => _pressColor,
DrawMode.HoverPressed => _pressColor,
_ => SelfModulate
};
if (TrueTexture != null && FalseTexture != null)
DrawTexture(State ? TrueTexture : FalseTexture, Vector2.Zero);
}
public override void _Ready() {
_baseColor = GetThemeColor("font_color", "Button");
_hoverColor = GetThemeColor("font_hover_color", "Button");
_pressColor = GetThemeColor("font_pressed_color", "Button");
}
}

8
svg_to_png.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/sh
if [ "$#" -lt 2 ]; then
echo "Usage: $0 [SVG File] [height]"
exit 1
fi
inkscape --export-type="png" --export-background-opacity=0 --export-height=$2 "$1"