Square-based scene. Auto-centering. Silder demonstration for receptor mesh.

This commit is contained in:
Luke Hubmayer-Werner 2019-12-17 15:05:27 +10:30
parent 794e9dd4a0
commit 5a4def27b0
10 changed files with 220 additions and 69 deletions

View File

@ -1,15 +1,29 @@
extends "res://main.gd"
tool
extends Node2D
# Draw the bezel for radial gamemode
var center := Vector2(0.0, 0.0)
func _draw():
var bezel_colors := PoolColorArray([GameTheme.bezel_color])
var bezel_points: PoolVector2Array
var screen_height2 := screen_height/2.0
func arc_point_list(center: Vector2, radius: float, angle_from:=0.0, angle_to:=360.0, points:=20) -> PoolVector2Array:
var point_list = PoolVector2Array()
for i in range(points):
var angle = deg2rad(angle_from + i * (angle_to - angle_from) / (points-1))
# point_list.push_back(center + Vector2(cos(angle), sin(angle)) * radius)
point_list.push_back(center + polar2cartesian(radius, angle))
return point_list
draw_rect(Rect2(-screen_height2, -screen_height2, -x_margin, screen_height), GameTheme.bezel_color)
draw_rect(Rect2(screen_height2, -screen_height2, x_margin, screen_height), GameTheme.bezel_color)
func _draw():
# var bezel_colors := PoolColorArray([GameTheme.bezel_color])
var bezel_colors := PoolColorArray([Color.red])
var bezel_points: PoolVector2Array
var screen_size = $"/root".get_visible_rect().size
var screen_height = 1080 # min(screen_size.x, screen_size.y)
var screen_height2 = screen_height/2.0
# draw_rect(Rect2(-screen_height2, -screen_height2, -x_margin, screen_height), GameTheme.bezel_color)
# draw_rect(Rect2(screen_height2, -screen_height2, x_margin, screen_height), GameTheme.bezel_color)
bezel_points = arc_point_list(center, screen_height2, 0, -90)
bezel_points.push_back(Vector2(screen_height2, -screen_height2))
@ -26,3 +40,6 @@ func _draw():
bezel_points = arc_point_list(center, screen_height2, -270, -360)
bezel_points.push_back(Vector2(screen_height2, screen_height2))
draw_polygon(bezel_points, bezel_colors)
func _ready():
$"/root".connect("size_changed", self, "update")

View File

@ -1,3 +1,4 @@
tool
extends Node
var receptor_ring_radius := 460.0

View File

@ -17,6 +17,11 @@ const TOUCHBUTTON_MAX_DIST := 1.05
const BUTTON_MIN_DIST := TOUCHBUTTON_MAX_DIST
const BUTTON_MAX_DIST := 1.25
func resize():
var screen_size = $"/root".get_visible_rect().size
rect_position = -screen_size*0.5
rect_size = screen_size
func _init():
buttons_pressed.resize(Rules.COLS)
touchbuttons_pressed.resize(Rules.COLS)
@ -28,6 +33,8 @@ func _ready():
set_process_unhandled_input(true) # process user input
set_fingers(0)
# connect("button_pressed", self, "print_pressed")
$"/root".connect("size_changed", self, "resize")
resize()
func print_pressed(col: int):

25
Menu.gd
View File

@ -1,3 +1,4 @@
tool
extends Node2D
var song_defs = {}
@ -289,7 +290,7 @@ func _draw_score_screen(center: Vector2) -> Array:
notecount_total += score # Kinda redundant, will probably refactor eventually
note_count += score
note_score += score * judge_scores[j]
draw_string_centered(TitleFont, Vector2(x2+x_spacing*(len(judgestrs)+1), y_row), "%2.2f%%"%(note_score/note_count*100.0), Color(0.95, 0.95, 1.0))
draw_string_centered(TitleFont, Vector2(x2+x_spacing*(len(judgestrs)+1), y_row), "%2.2f%%"%(note_score/max(note_count, 1)*100.0), Color(0.95, 0.95, 1.0))
total_score += note_score * notetype_weights[i]
total_scoremax += note_count * notetype_weights[i]
@ -325,6 +326,17 @@ func _draw_score_screen(center: Vector2) -> Array:
draw_string_centered(TitleFont, Vector2(x-210, 320), "Saved", Color(0.95, 0.95, 1.0))
return touchrects
func _draw_gameplay(center: Vector2) -> Array:
var touchrects = []
var x = center.x
var y = center.y
var rect_songselect := Rect2(-960.0, 440.0, 100.0, 100.0)
draw_rect(rect_songselect, Color.red)
draw_string_centered(TitleFont, Vector2(-910, 470), "Stop", Color(0.95, 0.95, 1.0))
touchrects.append({rect=rect_songselect, action="stop"})
return touchrects
func _draw():
var songs = len(song_defs)
@ -373,6 +385,7 @@ func _draw():
pass
MenuMode.GAMEPLAY:
GameTheme.set_screen_filter_alpha(0.0)
touch_rects[menu_mode] = _draw_gameplay(center)
MenuMode.SCORE_SCREEN:
GameTheme.set_screen_filter_alpha(1.0)
touch_rects[menu_mode] = _draw_score_screen(center)
@ -402,6 +415,12 @@ func touch_select_chart(touchdict):
self.selected_difficulty = touchdict.chart_idx
SFXPlayer.play(SFXPlayer.Type.NON_POSITIONAL, self, snd_interact, -4.5)
func touch_gameplay(touchdict):
if touchdict.has("action"):
SFXPlayer.play(SFXPlayer.Type.NON_POSITIONAL, self, snd_interact, 0.0)
if touchdict.action == "stop":
$"/root/main/NoteHandler".stop()
func touch_score_screen(touchdict):
if touchdict.has("next_menu"):
SFXPlayer.play(SFXPlayer.Type.NON_POSITIONAL, self, snd_interact, 0.0)
@ -436,6 +455,10 @@ func _input(event):
for d in touch_rects[MenuMode.CHART_SELECT]:
if d.rect.has_point(pos):
touch_select_chart(d)
MenuMode.GAMEPLAY:
for d in touch_rects[MenuMode.GAMEPLAY]:
if d.rect.has_point(pos):
touch_gameplay(d)
MenuMode.SCORE_SCREEN:
for d in touch_rects[MenuMode.SCORE_SCREEN]:
if d.rect.has_point(pos):

View File

@ -1,4 +1,6 @@
extends "res://main.gd"
extends Node2D
var screen_height := 1080
# This script will draw all note events.
signal finished_song(song_key, score_data)
@ -537,6 +539,11 @@ func load_track(data: Dictionary, difficulty_idx: int):
$meshinstance.material.set_shader_param("screen_size", get_viewport().get_size())
$meshinstance.set_texture(tex)
func stop():
$"/root/main/music".stop()
$"/root/main/video".stop()
# running = false
next_note_to_load = 1000000 # Hacky but whatever
func intro_click():
SFXPlayer.play(SFXPlayer.Type.NON_POSITIONAL, self, snd_count_in)
@ -656,7 +663,7 @@ func _process(delta):
# if (len(active_notes) < 1) and (next_note_to_load >= len(all_notes)) and (time > 10.0) and not get_node("/root/main/video").is_playing():
# time = -10.0
# next_note_to_load = 0
if (len(active_notes) < 1) and (next_note_to_load >= len(all_notes)) and not get_node("/root/main/music").is_playing():
if (len(active_notes) < 1) and (next_note_to_load >= len(all_notes)) and not get_node("/root/main/music").is_playing() and (len(active_judgement_texts) < 1):
self.running = false
self.timers_set = false
emit_signal("finished_song", song_key, scores)

View File

@ -1,4 +1,5 @@
extends "res://main.gd"
tool
extends Node2D
var ring_px := 4
var receptor_px := 24
@ -6,25 +7,83 @@ var shadow_px := 5
var shadow_color := Color.black
var center := Vector2(0.0, 0.0)
func _draw():
# Screen filter
draw_rect(Rect2(-screen_height/2, -screen_height/2, screen_height, screen_height), GameTheme.screen_filter)
func make_ring_mesh(inner_vertices: int, thickness: float, radius: float, skew=0.5):
# This makes a trianglestrip around the ring, consisting of chords on the inside and tangents on the outside.
# The goal is to exchange some fragment and vertex processing load:
# - a full quad of the ring would be the maximum fragment load and minimum vertex load
# - a complex mesh closely following the outline of the ring would minimize discarded fragments at the cost of increased vertex processing
# - the ideal workload ratio is probably different for each GPU and also depends on other things our program is doing
assert(inner_vertices >= 3)
assert(thickness > 0.0)
assert(radius > 0.0)
# While values of 3 and 4 are mathematically possible, they result in half of the trianglestrip being degenerate for thin lines.
# Only values of 5 and above should be used practically.
var vertices = inner_vertices * 2
# For simplicity's sake, the width of the ring will be the full thickness at the receptor points.
# For high vertex counts a slightly more optimal mesh could be constructed based on the thickness at each arc of the ring and where it would be intersected by the outer tangent.
# Essentially, we will be making an inner polygon and an outer polygon.
var angle_increment = TAU/float(inner_vertices)
var angle_outer_offset = skew*angle_increment
var r1 = radius - thickness*0.5
# Outer polygon side-length = inner side-length / sin(inside angle/2)
# inside angle for a polygon is pi-tau/n. We already precalculated tau/n for other purposes.
var r2 = (radius + thickness*0.5)/sin((PI-angle_increment)/2)
var vertex_list = PoolVector2Array()
for i in inner_vertices:
var angle_i = i * angle_increment
var angle_o = angle_i + angle_outer_offset
vertex_list.push_back(polar2cartesian(r1, angle_i))
vertex_list.push_back(polar2cartesian(r2, angle_o))
return vertex_list
func triangle_area(a: Vector2, b: Vector2, c: Vector2) -> float:
return 0.5 * abs((a.x-c.x)*(b.y-a.y) - (a.x-b.x)*(c.y-a.y))
func arc_point_list(center: Vector2, radius: float, angle_from:=0.0, angle_to:=360.0, points:=90) -> PoolVector2Array:
var point_list = PoolVector2Array()
for i in range(points):
var angle = deg2rad(angle_from + i * (angle_to - angle_from) / (points-1))
# point_list.push_back(center + Vector2(cos(angle), sin(angle)) * radius)
point_list.push_back(center + polar2cartesian(radius, angle))
return point_list
func _draw():
# Receptor ring
var receptor_circle := arc_point_list(center, GameTheme.receptor_ring_radius, 0.0, 360.0, 360)
var receptor_centers := arc_point_list(center, GameTheme.receptor_ring_radius, Rules.FIRST_COLUMN_ANGLE_DEG, Rules.FIRST_COLUMN_ANGLE_DEG+360.0-Rules.COLS_ANGLE_DEG, Rules.COLS)
# Shadows
for i in range(len(receptor_circle)-1):
draw_line(receptor_circle[i], receptor_circle[i+1], shadow_color, ring_px + shadow_px, true)
for i in range(len(receptor_centers)):
draw_circle(receptor_centers[i], (receptor_px + shadow_px)/2, shadow_color)
# Foregrounds
# # Shadows
# for i in range(len(receptor_circle)-1):
# draw_line(receptor_circle[i], receptor_circle[i+1], shadow_color, ring_px + shadow_px, true)
## draw_line(receptor_circle[i], receptor_circle[i+1], shadow_color)
# for i in range(len(receptor_centers)):
# draw_circle(receptor_centers[i], (receptor_px + shadow_px)/2, shadow_color)
#
# # Foregrounds
for i in range(len(receptor_circle)-1):
draw_line(receptor_circle[i], receptor_circle[i+1], GameTheme.receptor_color, ring_px, true)
# draw_line(receptor_circle[i], receptor_circle[i+1], GameTheme.receptor_color)
for i in range(len(receptor_centers)):
draw_circle(receptor_centers[i], receptor_px/2, GameTheme.receptor_color)
var mesh_v = $VerticesSlider.value
var skew = $SkewSlider.value
var dbg_color = Color.red
var ring_vertices = make_ring_mesh(mesh_v, receptor_px + shadow_px, GameTheme.receptor_ring_radius, skew)
var estimated_area = 0.0
var ideal_ring_area = PI * (pow(GameTheme.receptor_ring_radius+(receptor_px+shadow_px)/2, 2) - pow(GameTheme.receptor_ring_radius-(receptor_px+shadow_px)/2, 2))
var l = len(ring_vertices)
for i in l:
draw_line(ring_vertices[i], ring_vertices[(i+1)%l], dbg_color)
draw_line(ring_vertices[i], ring_vertices[(i+2)%l], dbg_color, 2.0)
estimated_area += triangle_area(ring_vertices[i], ring_vertices[(i+1)%l], ring_vertices[(i+2)%l])
var quad_area = 4*pow(GameTheme.receptor_ring_radius+(receptor_px+shadow_px)/2, 2)
$"/root/main/InputHandler".text = "Vertices: %d*2 Skew: %.3f\nArea: %.0f\n(%.0f%% ideal ring)\n(%.0f%% quad)"%[mesh_v, skew, estimated_area, 100.0*estimated_area/ideal_ring_area, 100.0*estimated_area/quad_area]
func _ready():
GameTheme.connect("screen_filter_changed", self, "update")
$"/root".connect("size_changed", self, "update")
func _process(delta):
if not Engine.editor_hint:
update()

9
ScreenFilter.gd Normal file
View File

@ -0,0 +1,9 @@
extends Node2D
func _draw():
var screen_size = $"/root".get_visible_rect().size
var screen_height = max(screen_size.x, screen_size.y)
draw_rect(Rect2(-screen_height/2, -screen_height/2, screen_height, screen_height), GameTheme.screen_filter)
func _ready():
GameTheme.connect("screen_filter_changed", self, "update")

30
main.gd
View File

@ -2,24 +2,20 @@ extends Node2D
# member variables
var screen_height := 1080
var x_margin := (1920 - screen_height)/2
var x_margin := 0.0
var y_margin := 0.0
var screen_center := Vector2(1920/2, screen_height/2)
func arc_point_list(center: Vector2, radius: float, angle_from:=0.0, angle_to:=360.0, points:=90) -> PoolVector2Array:
var point_list = PoolVector2Array()
for i in range(points):
var angle = deg2rad(angle_from + i * (angle_to - angle_from) / (points-1))
# point_list.push_back(center + Vector2(cos(angle), sin(angle)) * radius)
point_list.push_back(center + polar2cartesian(radius, angle))
return point_list
# Called when the node enters the scene tree for the first time.
#func _ready():
# pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta):
# pass
func resize():
var screen_size = $"/root".get_visible_rect().size
screen_center = screen_size*0.5
position = screen_center
screen_height = screen_size.y
x_margin = max((screen_size.x - screen_size.y)/2.0, 0.0)
y_margin = max((screen_size.y - screen_size.x)/2.0, 0.0)
func _ready():
$"/root".connect("size_changed", self, "resize")
resize()

View File

@ -1,21 +1,22 @@
[gd_scene load_steps=16 format=2]
[gd_scene load_steps=17 format=2]
[ext_resource path="res://main.gd" type="Script" id=1]
[ext_resource path="res://video.gd" type="Script" id=2]
[ext_resource path="res://Receptors.gd" type="Script" id=3]
[ext_resource path="res://NoteHandler.gd" type="Script" id=4]
[ext_resource path="res://assets/text-4k.png" type="Texture" id=5]
[ext_resource path="res://shaders/notelines.shader" type="Shader" id=6]
[ext_resource path="res://shaders/notemesh.shader" type="Shader" id=7]
[ext_resource path="res://Menu.gd" type="Script" id=8]
[ext_resource path="res://shaders/scoretext.tres" type="Material" id=9]
[ext_resource path="res://ScoreText.gd" type="Script" id=10]
[ext_resource path="res://Bezel.gd" type="Script" id=11]
[ext_resource path="res://assets/NotoSans.tres" type="DynamicFont" id=12]
[ext_resource path="res://InputHandler.gd" type="Script" id=13]
[ext_resource path="res://ScreenFilter.gd" type="Script" id=3]
[ext_resource path="res://Receptors.gd" type="Script" id=4]
[ext_resource path="res://NoteHandler.gd" type="Script" id=5]
[ext_resource path="res://assets/text-4k.png" type="Texture" id=6]
[ext_resource path="res://shaders/notelines.shader" type="Shader" id=7]
[ext_resource path="res://shaders/notemesh.shader" type="Shader" id=8]
[ext_resource path="res://Menu.gd" type="Script" id=9]
[ext_resource path="res://shaders/scoretext.tres" type="Material" id=10]
[ext_resource path="res://ScoreText.gd" type="Script" id=11]
[ext_resource path="res://Bezel.gd" type="Script" id=12]
[ext_resource path="res://assets/NotoSans.tres" type="DynamicFont" id=13]
[ext_resource path="res://InputHandler.gd" type="Script" id=14]
[sub_resource type="ShaderMaterial" id=1]
shader = ExtResource( 6 )
shader = ExtResource( 7 )
shader_param/line_color = Plane( 0.8, 0.8, 1, 0.8 )
shader_param/line_color_double = Plane( 1, 1, 0.6, 0.9 )
shader_param/dot_color = Plane( 1, 1, 1, 0.8 )
@ -27,18 +28,18 @@ shader_param/dot_fullbright_thickness = 0.013
shader_param/max_angle = 1.0708
[sub_resource type="ShaderMaterial" id=2]
shader = ExtResource( 7 )
shader = ExtResource( 8 )
shader_param/bps = null
shader_param/star_color = null
shader_param/held_color = null
shader_param/screen_size = null
[node name="main" type="Node2D"]
position = Vector2( 960, 540 )
position = Vector2( 540, 540 )
script = ExtResource( 1 )
__meta__ = {
"_edit_horizontal_guides_": [ ],
"_edit_vertical_guides_": [ 420.85, 1500.91 ]
"_edit_vertical_guides_": [ ]
}
[node name="music" type="AudioStreamPlayer" parent="."]
@ -58,16 +59,44 @@ __meta__ = {
"_edit_use_anchors_": false
}
[node name="Receptors" type="Node2D" parent="."]
[node name="ScreenFilter" type="Node2D" parent="."]
script = ExtResource( 3 )
[node name="NoteHandler" type="Node2D" parent="."]
[node name="Receptors" type="Node2D" parent="."]
script = ExtResource( 4 )
[node name="SkewSlider" type="HSlider" parent="Receptors"]
margin_left = -200.0
margin_top = -30.0
margin_right = 200.0
margin_bottom = 30.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
size_flags_vertical = 3
max_value = 1.0
step = 0.001
tick_count = 3
ticks_on_borders = true
[node name="VerticesSlider" type="HSlider" parent="Receptors"]
margin_left = -200.0
margin_top = -100.0
margin_right = 200.0
margin_bottom = -84.0
min_value = 3.0
max_value = 72.0
value = 8.0
tick_count = 2
ticks_on_borders = false
[node name="NoteHandler" type="Node2D" parent="."]
script = ExtResource( 5 )
[node name="SlideTrailHandler" type="Node2D" parent="NoteHandler"]
[node name="JudgeText" type="MeshInstance2D" parent="NoteHandler"]
texture = ExtResource( 5 )
texture = ExtResource( 6 )
[node name="notelines" type="MeshInstance2D" parent="NoteHandler"]
material = SubResource( 1 )
@ -76,20 +105,23 @@ material = SubResource( 1 )
material = SubResource( 2 )
[node name="Menu" type="Node2D" parent="."]
script = ExtResource( 8 )
script = ExtResource( 9 )
[node name="ScoreText" type="Node2D" parent="Menu"]
material = ExtResource( 9 )
script = ExtResource( 10 )
[node name="Bezel" type="Node2D" parent="."]
material = ExtResource( 10 )
script = ExtResource( 11 )
[node name="Bezel" type="Node2D" parent="."]
script = ExtResource( 12 )
[node name="InputHandler" type="Label" parent="."]
margin_left = -960.0
margin_left = -540.0
margin_top = -540.0
margin_right = 960.0
margin_right = 540.0
margin_bottom = 540.0
custom_fonts/font = ExtResource( 12 )
custom_fonts/font = ExtResource( 13 )
text = "Fingers on the screen:"
script = ExtResource( 13 )
script = ExtResource( 14 )
__meta__ = {
"_edit_lock_": true
}

View File

@ -44,12 +44,12 @@ gdscript/warnings/integer_division=false
[display]
window/size/width=1920
window/size/width=1080
window/size/height=1080
window/size/fullscreen=true
window/handheld/orientation="sensor"
window/stretch/mode="2d"
window/stretch/aspect="keep_height"
window/stretch/aspect="expand"
[gdnative]