Initial commit
This commit is contained in:
commit
08034bb71d
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Godot-specific ignores
|
||||||
|
.import/
|
||||||
|
export.cfg
|
||||||
|
export_presets.cfg
|
||||||
|
|
||||||
|
# Imported translations (automatically generated from CSV files)
|
||||||
|
*.translation
|
||||||
|
|
||||||
|
# Mono-specific ignores
|
||||||
|
.mono/
|
||||||
|
data_*/
|
116
Circle.gd
Normal file
116
Circle.gd
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
extends Object
|
||||||
|
|
||||||
|
const Set = preload("res://Set.gd")
|
||||||
|
|
||||||
|
var position: Vector2
|
||||||
|
var radius: float
|
||||||
|
|
||||||
|
func _init(p_position: Vector2 = Vector2(), p_radius: float = 0.0):
|
||||||
|
position = p_position
|
||||||
|
radius = p_radius
|
||||||
|
|
||||||
|
func contains_point(p: Vector2):
|
||||||
|
return position.distance_squared_to(p) <= radius * radius + 0.1
|
||||||
|
|
||||||
|
func contains_all_points(ps: Array):
|
||||||
|
for p in ps:
|
||||||
|
if !contains_point(p):
|
||||||
|
return false
|
||||||
|
return true
|
||||||
|
|
||||||
|
func circumscribe_two_points(a: Vector2, b: Vector2):
|
||||||
|
position = a.linear_interpolate(b, 0.5)
|
||||||
|
radius = a.distance_to(b) / 2.0
|
||||||
|
|
||||||
|
func circumscribe_three_points(a: Vector2, b: Vector2, c: Vector2):
|
||||||
|
var bary_mat := [b - a, c - a]
|
||||||
|
var det = bary_mat[0].x * bary_mat[1].y - bary_mat[1].x * bary_mat[0].y
|
||||||
|
var area = 0.5 * det
|
||||||
|
|
||||||
|
if area < 0.001:
|
||||||
|
position = a
|
||||||
|
radius = 0.0
|
||||||
|
return
|
||||||
|
|
||||||
|
position = Vector2(
|
||||||
|
a.x + 1.0 / (4.0 * area) * (bary_mat[1].y * a.distance_squared_to(b) - bary_mat[0].y * a.distance_squared_to(c)),
|
||||||
|
a.y + 1.0 / (4.0 * area) * (bary_mat[0].x * a.distance_squared_to(c) - bary_mat[1].x * a.distance_squared_to(b))
|
||||||
|
)
|
||||||
|
radius = position.distance_to(a)
|
||||||
|
|
||||||
|
func circumscribe(points: Array):
|
||||||
|
var n = len(points)
|
||||||
|
assert(n > 1)
|
||||||
|
|
||||||
|
position = Vector2(0, 0)
|
||||||
|
radius = INF
|
||||||
|
|
||||||
|
if n == 2:
|
||||||
|
circumscribe_two_points(points[0], points[1])
|
||||||
|
return
|
||||||
|
elif n == 3:
|
||||||
|
circumscribe_three_points(points[0], points[1], points[2])
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check every two points
|
||||||
|
for i in range(n):
|
||||||
|
for j in range(n):
|
||||||
|
if i == j: continue
|
||||||
|
var c = get_script().new()
|
||||||
|
c.circumscribe_two_points(points[i], points[j])
|
||||||
|
if c.radius < radius and c.contains_all_points(points):
|
||||||
|
position = c.position
|
||||||
|
radius = c.radius
|
||||||
|
|
||||||
|
# Check every three points
|
||||||
|
for i in range(n):
|
||||||
|
for j in range(n):
|
||||||
|
for k in range(n):
|
||||||
|
if i == j or j == k or i == k: continue
|
||||||
|
var c = get_script().new()
|
||||||
|
c.circumscribe_three_points(points[i], points[j], points[k])
|
||||||
|
if c.radius < radius and c.contains_all_points(points):
|
||||||
|
position = c.position
|
||||||
|
radius = c.radius
|
||||||
|
|
||||||
|
func circumscribe2_internal(input: Set, support: Set):
|
||||||
|
var c = get_script().new()
|
||||||
|
if !input.empty():
|
||||||
|
var input_prime: Set = input.duplicate()
|
||||||
|
var p: Vector2 = input_prime.pop_random() # remove P from Input
|
||||||
|
|
||||||
|
c.circumscribe2_internal(input_prime, support);
|
||||||
|
if c.contains_point(p):
|
||||||
|
return c
|
||||||
|
else:
|
||||||
|
var support_prime = support.duplicate()
|
||||||
|
support_prime.add(p)
|
||||||
|
|
||||||
|
c.circumscribe2_internal(input_prime, support_prime)
|
||||||
|
return c
|
||||||
|
else:
|
||||||
|
var support_values = support.values()
|
||||||
|
if len(support_values) == 2:
|
||||||
|
c.circumscribe_two_points(support_values[0], support_values[1])
|
||||||
|
elif len(support_values) == 3:
|
||||||
|
c.circumscribe_three_points(support_values[0], support_values[1], support_values[2])
|
||||||
|
return c
|
||||||
|
|
||||||
|
func circumscribe2(points: Array):
|
||||||
|
var n = len(points)
|
||||||
|
assert(n > 1)
|
||||||
|
|
||||||
|
if n == 2:
|
||||||
|
circumscribe_two_points(points[0], points[1])
|
||||||
|
return
|
||||||
|
elif n == 3:
|
||||||
|
circumscribe_three_points(points[0], points[1], points[2])
|
||||||
|
return
|
||||||
|
|
||||||
|
var points_set = Set.new()
|
||||||
|
points_set.add_all(points)
|
||||||
|
var c = circumscribe2_internal(points_set, Set.new())
|
||||||
|
position = c.position
|
||||||
|
radius = c.radius
|
||||||
|
|
||||||
|
|
18
Global.gd
Normal file
18
Global.gd
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
|
||||||
|
# Declare member variables here. Examples:
|
||||||
|
# var a = 2
|
||||||
|
# var b = "text"
|
||||||
|
|
||||||
|
|
||||||
|
# Called when the node enters the scene tree for the first time.
|
||||||
|
func _init():
|
||||||
|
OS.set_window_position(
|
||||||
|
OS.get_screen_position(OS.get_current_screen()) +
|
||||||
|
OS.get_screen_size()*0.5 - OS.get_window_size()*0.5)
|
||||||
|
|
||||||
|
|
||||||
|
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||||
|
#func _process(delta):
|
||||||
|
# pass
|
28
Main.tscn
Normal file
28
Main.tscn
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
[gd_scene load_steps=3 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://MinimumAreaCircle.gd" type="Script" id=1]
|
||||||
|
[ext_resource path="res://Point.tscn" type="PackedScene" id=2]
|
||||||
|
|
||||||
|
[node name="Main" type="Node2D"]
|
||||||
|
|
||||||
|
[node name="Camera2D" type="Camera2D" parent="."]
|
||||||
|
position = Vector2( 2, 2 )
|
||||||
|
current = true
|
||||||
|
|
||||||
|
[node name="MinimumAreaCircle" type="Node2D" parent="."]
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
color = Color( 0.305882, 0.34902, 0.827451, 1 )
|
||||||
|
|
||||||
|
[node name="Point" parent="MinimumAreaCircle" instance=ExtResource( 2 )]
|
||||||
|
|
||||||
|
[node name="Point2" parent="MinimumAreaCircle" instance=ExtResource( 2 )]
|
||||||
|
position = Vector2( -218, -131 )
|
||||||
|
|
||||||
|
[node name="Point3" parent="MinimumAreaCircle" instance=ExtResource( 2 )]
|
||||||
|
position = Vector2( -186, -51 )
|
||||||
|
|
||||||
|
[node name="Point4" parent="MinimumAreaCircle" instance=ExtResource( 2 )]
|
||||||
|
position = Vector2( -285, 34 )
|
||||||
|
|
||||||
|
[node name="Point5" parent="MinimumAreaCircle" instance=ExtResource( 2 )]
|
||||||
|
position = Vector2( -173, 87 )
|
24
MinimumAreaCircle.gd
Normal file
24
MinimumAreaCircle.gd
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
extends Node2D
|
||||||
|
|
||||||
|
const Circle = preload("res://Circle.gd")
|
||||||
|
|
||||||
|
onready var circle: Circle = Circle.new()
|
||||||
|
export var color: Color = Color.red
|
||||||
|
|
||||||
|
var selected_idx = 0
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
update_circle()
|
||||||
|
for child in get_children():
|
||||||
|
if child is CanvasItem:
|
||||||
|
child.connect("moved", self, "update_circle")
|
||||||
|
|
||||||
|
func update_circle():
|
||||||
|
var ps = []
|
||||||
|
for child in get_children():
|
||||||
|
ps.append(child.position)
|
||||||
|
circle.circumscribe(ps)
|
||||||
|
update()
|
||||||
|
|
||||||
|
func _draw():
|
||||||
|
draw_arc(circle.position, circle.radius, 0, TAU, 200, color, 2.0, true)
|
17
Point.gd
Normal file
17
Point.gd
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
extends Node2D
|
||||||
|
|
||||||
|
signal moved
|
||||||
|
|
||||||
|
var dragging := false
|
||||||
|
|
||||||
|
func _unhandled_input(event):
|
||||||
|
if event is InputEventMouseMotion and dragging and !event.has_meta("handled"):
|
||||||
|
position = get_viewport().canvas_transform.xform_inv(event.position)
|
||||||
|
emit_signal("moved")
|
||||||
|
event.set_meta("handled", true)
|
||||||
|
elif event.is_action_released("drag"):
|
||||||
|
dragging = false
|
||||||
|
|
||||||
|
func _on_HitBox_input_event(viewport, event: InputEvent, shape_idx):
|
||||||
|
if event.is_action_pressed("drag"):
|
||||||
|
dragging = true
|
19
Point.tscn
Normal file
19
Point.tscn
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[gd_scene load_steps=4 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://point.png" type="Texture" id=1]
|
||||||
|
[ext_resource path="res://Point.gd" type="Script" id=2]
|
||||||
|
|
||||||
|
[sub_resource type="CircleShape2D" id=1]
|
||||||
|
radius = 14.0
|
||||||
|
|
||||||
|
[node name="Point" type="Sprite"]
|
||||||
|
position = Vector2( -292, -74 )
|
||||||
|
texture = ExtResource( 1 )
|
||||||
|
script = ExtResource( 2 )
|
||||||
|
|
||||||
|
[node name="HitBox" type="Area2D" parent="."]
|
||||||
|
|
||||||
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="HitBox"]
|
||||||
|
shape = SubResource( 1 )
|
||||||
|
|
||||||
|
[connection signal="input_event" from="HitBox" to="." method="_on_HitBox_input_event"]
|
52
Set.gd
Normal file
52
Set.gd
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
extends Object
|
||||||
|
|
||||||
|
var _values: Dictionary
|
||||||
|
|
||||||
|
func _init():
|
||||||
|
_values = Dictionary()
|
||||||
|
|
||||||
|
func size() -> int:
|
||||||
|
return _values.size()
|
||||||
|
|
||||||
|
func empty() -> bool:
|
||||||
|
return _values.size() == 0
|
||||||
|
|
||||||
|
func add(value):
|
||||||
|
_values[value] = true
|
||||||
|
|
||||||
|
func add_all(values):
|
||||||
|
for value in values:
|
||||||
|
add(value)
|
||||||
|
|
||||||
|
func remove(value):
|
||||||
|
_values.erase(value)
|
||||||
|
|
||||||
|
func remove_all(values):
|
||||||
|
for value in values:
|
||||||
|
remove(value)
|
||||||
|
|
||||||
|
func get_random():
|
||||||
|
return _values.keys()[randi() % _values.size()]
|
||||||
|
|
||||||
|
func pop_random():
|
||||||
|
assert(size() > 0)
|
||||||
|
var value = get_random()
|
||||||
|
remove(value)
|
||||||
|
return value
|
||||||
|
|
||||||
|
func values() -> Array:
|
||||||
|
return _values.keys()
|
||||||
|
|
||||||
|
func has(value) -> bool:
|
||||||
|
return _values.has(value)
|
||||||
|
|
||||||
|
func has_all(values) -> bool:
|
||||||
|
return _values.has_all(values)
|
||||||
|
|
||||||
|
func duplicate():
|
||||||
|
var new_set = get_script().new()
|
||||||
|
new_set._values = _values.duplicate()
|
||||||
|
return new_set
|
||||||
|
|
||||||
|
func clear():
|
||||||
|
_values.clear()
|
7
default_env.tres
Normal file
7
default_env.tres
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[gd_resource type="Environment" load_steps=2 format=2]
|
||||||
|
|
||||||
|
[sub_resource type="ProceduralSky" id=1]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
background_mode = 2
|
||||||
|
background_sky = SubResource( 1 )
|
35
icon.png.import
Normal file
35
icon.png.import
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://icon.png"
|
||||||
|
dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/bptc_ldr=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=0
|
||||||
|
flags/filter=true
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
process/invert_color=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=true
|
||||||
|
svg/scale=1.0
|
35
point.png.import
Normal file
35
point.png.import
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/point.png-85d91f0a7902375f86d31abcb57f3516.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://point.png"
|
||||||
|
dest_files=[ "res://.import/point.png-85d91f0a7902375f86d31abcb57f3516.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/bptc_ldr=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=0
|
||||||
|
flags/filter=true
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
process/invert_color=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=true
|
||||||
|
svg/scale=1.0
|
64
project.godot
Normal file
64
project.godot
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
; Engine configuration file.
|
||||||
|
; It's best edited using the editor UI and not directly,
|
||||||
|
; since the parameters that go here are not all obvious.
|
||||||
|
;
|
||||||
|
; Format:
|
||||||
|
; [section] ; section goes between []
|
||||||
|
; param=value ; assign values to parameters
|
||||||
|
|
||||||
|
config_version=4
|
||||||
|
|
||||||
|
[application]
|
||||||
|
|
||||||
|
config/name="minareacircle"
|
||||||
|
run/main_scene="res://Main.tscn"
|
||||||
|
config/icon="res://icon.png"
|
||||||
|
|
||||||
|
[autoload]
|
||||||
|
|
||||||
|
Global="*res://Global.gd"
|
||||||
|
|
||||||
|
[input]
|
||||||
|
|
||||||
|
ui_left={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777231,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
|
||||||
|
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":14,"pressure":0.0,"pressed":false,"script":null)
|
||||||
|
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":0,"physical_scancode":65,"unicode":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
ui_right={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777233,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
|
||||||
|
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":15,"pressure":0.0,"pressed":false,"script":null)
|
||||||
|
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":0,"physical_scancode":68,"unicode":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
ui_up={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777232,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
|
||||||
|
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":12,"pressure":0.0,"pressed":false,"script":null)
|
||||||
|
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":0,"physical_scancode":87,"unicode":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
ui_down={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777234,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
|
||||||
|
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":13,"pressure":0.0,"pressed":false,"script":null)
|
||||||
|
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":0,"physical_scancode":83,"unicode":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
drag={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":1,"pressed":false,"doubleclick":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
[physics]
|
||||||
|
|
||||||
|
common/enable_pause_aware_picking=true
|
||||||
|
|
||||||
|
[rendering]
|
||||||
|
|
||||||
|
quality/depth/hdr=false
|
||||||
|
environment/default_environment="res://default_env.tres"
|
Loading…
x
Reference in New Issue
Block a user