Initial import

This commit is contained in:
Feufochmar 2021-12-19 18:02:05 +01:00
commit cc88dc9f9e
42 changed files with 2610 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.import/

BIN
LibertinusSans-Regular.otf Normal file

Binary file not shown.

7
default_env.tres Normal file
View 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 )

48
entity/chest.tscn Normal file
View File

@ -0,0 +1,48 @@
[gd_scene load_steps=9 format=2]
[sub_resource type="CubeMesh" id=1]
size = Vector3( 0.2, 0.2, 0.6 )
[sub_resource type="OpenSimplexNoise" id=2]
period = 12.0
persistence = 0.3
lacunarity = 4.0
[sub_resource type="NoiseTexture" id=3]
height = 8
noise = SubResource( 2 )
[sub_resource type="SpatialMaterial" id=4]
albedo_color = Color( 0.756863, 0.658824, 0.321569, 1 )
albedo_texture = SubResource( 3 )
[sub_resource type="CylinderMesh" id=5]
top_radius = 0.1
bottom_radius = 0.1
height = 0.59
[sub_resource type="OpenSimplexNoise" id=6]
period = 12.0
persistence = 0.3
lacunarity = 4.0
[sub_resource type="NoiseTexture" id=7]
height = 8
bump_strength = 20.0
noise = SubResource( 6 )
[sub_resource type="SpatialMaterial" id=8]
albedo_color = Color( 0.756863, 0.658824, 0.321569, 1 )
albedo_texture = SubResource( 7 )
[node name="Chest" type="Spatial"]
[node name="Bottom" type="MeshInstance" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0 )
mesh = SubResource( 1 )
material/0 = SubResource( 4 )
[node name="Top" type="MeshInstance" parent="."]
transform = Transform( 1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 0.2, 0 )
mesh = SubResource( 5 )
material/0 = SubResource( 8 )

15
entity/entrance.tscn Normal file
View File

@ -0,0 +1,15 @@
[gd_scene load_steps=3 format=2]
[sub_resource type="CylinderMesh" id=1]
top_radius = 0.8
bottom_radius = 0.9
height = 0.1
[sub_resource type="SpatialMaterial" id=2]
albedo_color = Color( 0.913725, 0.929412, 0.341176, 1 )
[node name="Entrance" type="Spatial"]
[node name="MeshInstance" type="MeshInstance" parent="."]
mesh = SubResource( 1 )
material/0 = SubResource( 2 )

15
entity/exit.tscn Normal file
View File

@ -0,0 +1,15 @@
[gd_scene load_steps=3 format=2]
[sub_resource type="CylinderMesh" id=1]
top_radius = 0.8
bottom_radius = 0.9
height = 0.1
[sub_resource type="SpatialMaterial" id=2]
albedo_color = Color( 0.870588, 0.341176, 0.929412, 1 )
[node name="Exit" type="Spatial"]
[node name="MeshInstance" type="MeshInstance" parent="."]
mesh = SubResource( 1 )
material/0 = SubResource( 2 )

29
entity/ground.tscn Normal file
View File

@ -0,0 +1,29 @@
[gd_scene load_steps=5 format=2]
[sub_resource type="CubeMesh" id=5]
size = Vector3( 100, 2, 100 )
[sub_resource type="OpenSimplexNoise" id=2]
octaves = 8
period = 16.0
persistence = 0.75
lacunarity = 3.0
[sub_resource type="NoiseTexture" id=3]
width = 64
height = 64
seamless = true
noise = SubResource( 2 )
[sub_resource type="SpatialMaterial" id=4]
albedo_color = Color( 0.337255, 0.631373, 0.180392, 1 )
albedo_texture = SubResource( 3 )
uv1_scale = Vector3( 0.25, 1, 0.25 )
uv1_triplanar = true
[node name="Ground" type="Spatial"]
[node name="MeshInstance" type="MeshInstance" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0 )
mesh = SubResource( 5 )
material/0 = SubResource( 4 )

85
entity/player.gd Normal file
View File

@ -0,0 +1,85 @@
class_name Player
extends Spatial
# Parameters
var speed = 4 # m/s
var spin = PI/2 # rad/s
# By default, not moving and not turning
var moving = false
var turning = false
# When moving, these are not null
var moving_vel = null
var target_pos = null
var turning_ang = 0.0
var orig_ang = 0.0
var target_ang = 0.0
# Move at position
func teleport_at(v: Vector3):
transform.origin = v + Vector3(0, 0.5, 0)
# Look at a direction
func turn_at(dir):
match dir:
Direction.NORTH:
rotation.y = 0
Direction.SOUTH:
rotation.y = PI
Direction.EAST:
rotation.y = -PI/2
Direction.WEST:
rotation.y = PI/2
# Indicate if player is moving or turning
func in_movement():
return moving or turning
# Move forward
func move_forward():
if not in_movement():
moving = true
moving_vel = Vector3.FORWARD
moving_vel *= speed
target_pos = to_global(2 * Vector3.FORWARD)
func move_backward():
if not in_movement():
moving = true
moving_vel = Vector3.BACK
moving_vel *= speed
target_pos = to_global(2 * Vector3.BACK)
func turn_left():
if not in_movement():
turning = true
orig_ang = rotation.y
target_ang = rotation.y + PI/2
turning_ang = 0.0
func turn_right():
if not in_movement():
turning = true
orig_ang = rotation.y
target_ang = rotation.y - PI/2
turning_ang = 0.0
#
func _physics_process(delta):
if moving:
if transform.origin.distance_to(target_pos) < 0.01:
# Move at target pos
transform.origin = target_pos
moving = false
else:
var velocity = moving_vel * delta
translate_object_local(velocity)
if turning:
if abs(rotation.y - target_ang) < 0.05:
# set angle
rotation.y = target_ang
turning = false
else:
turning_ang += spin * delta
rotation.y = lerp_angle(orig_ang, target_ang, turning_ang)

39
entity/player.tscn Normal file
View File

@ -0,0 +1,39 @@
[gd_scene load_steps=4 format=2]
[ext_resource path="res://entity/player.gd" type="Script" id=1]
[sub_resource type="ProceduralSky" id=2]
sky_top_color = Color( 0.878431, 0.92549, 0.972549, 1 )
sky_horizon_color = Color( 0.117647, 0.219608, 0.172549, 1 )
ground_bottom_color = Color( 0.133333, 0.270588, 0.0196078, 1 )
ground_horizon_color = Color( 0.133333, 0.270588, 0.0196078, 1 )
sun_color = Color( 0.811765, 0.686275, 0.109804, 1 )
sun_latitude = 20.0
sun_longitude = 180.0
sun_angle_min = 2.0
[sub_resource type="Environment" id=1]
background_mode = 2
background_sky = SubResource( 2 )
background_color = Color( 0.301961, 0.458824, 0.454902, 1 )
ambient_light_color = Color( 1, 1, 1, 1 )
[node name="Player" type="Spatial"]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0 )
script = ExtResource( 1 )
[node name="Camera" type="Camera" parent="."]
environment = SubResource( 1 )
current = true
fov = 60.0
size = 2.0
far = 8192.0
[node name="RayCast_Center" type="RayCast" parent="."]
cast_to = Vector3( 0, 0, -8 )
[node name="RayCast_Left" type="RayCast" parent="."]
cast_to = Vector3( -4.25, 0, -6.75 )
[node name="RayCast_Right" type="RayCast" parent="."]
cast_to = Vector3( 4.25, 0, -6.75 )

26
entity/wall.tscn Normal file
View File

@ -0,0 +1,26 @@
[gd_scene load_steps=5 format=2]
[sub_resource type="CubeMesh" id=1]
size = Vector3( 2, 2, 0.2 )
[sub_resource type="OpenSimplexNoise" id=2]
period = 12.0
persistence = 0.3
lacunarity = 4.0
[sub_resource type="NoiseTexture" id=3]
width = 64
height = 4
noise = SubResource( 2 )
[sub_resource type="SpatialMaterial" id=4]
albedo_color = Color( 0.760784, 0.501961, 0.215686, 1 )
albedo_texture = SubResource( 3 )
uv1_triplanar = true
[node name="Wall" type="Spatial" groups=["map_block"]]
[node name="Mesh" type="MeshInstance" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0 )
mesh = SubResource( 1 )
material/0 = SubResource( 4 )

133
export_presets.cfg Normal file
View File

@ -0,0 +1,133 @@
[preset.0]
name="Windows Desktop"
platform="Windows Desktop"
runnable=true
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path="../exports/Ygdra/Windows/Ygdra.exe"
script_export_mode=1
script_encryption_key=""
[preset.0.options]
custom_template/debug=""
custom_template/release=""
binary_format/64_bits=true
binary_format/embed_pck=false
texture_format/bptc=false
texture_format/s3tc=true
texture_format/etc=false
texture_format/etc2=false
texture_format/no_bptc_fallbacks=true
codesign/enable=false
codesign/identity=""
codesign/password=""
codesign/timestamp=true
codesign/timestamp_server_url=""
codesign/digest_algorithm=1
codesign/description=""
codesign/custom_options=PoolStringArray( )
application/icon=""
application/file_version=""
application/product_version=""
application/company_name=""
application/product_name="Ygdra"
application/file_description=""
application/copyright=""
application/trademarks=""
[preset.1]
name="Mac OSX"
platform="Mac OSX"
runnable=true
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path="../exports/Ygdra/MacOS/Ygdra.zip"
script_export_mode=1
script_encryption_key=""
[preset.1.options]
custom_template/debug=""
custom_template/release=""
application/name="Ygdra"
application/info="Made with Godot Engine"
application/icon=""
application/identifier="fr.feufochmar.ygdra"
application/signature=""
application/app_category="Games"
application/short_version="1.0"
application/version="1.0"
application/copyright=""
display/high_res=false
privacy/camera_usage_description=""
privacy/microphone_usage_description=""
texture_format/s3tc=true
texture_format/etc=false
texture_format/etc2=false
[preset.2]
name="Linux/X11"
platform="Linux/X11"
runnable=true
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path="../exports/Ygdra/Linux/Ygdra.x86_64"
script_export_mode=1
script_encryption_key=""
[preset.2.options]
custom_template/debug=""
custom_template/release=""
binary_format/64_bits=true
binary_format/embed_pck=false
texture_format/bptc=false
texture_format/s3tc=true
texture_format/etc=false
texture_format/etc2=false
texture_format/no_bptc_fallbacks=true
[preset.3]
name="HTML5"
platform="HTML5"
runnable=true
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path="../exports/Ygdra/HTML/index.html"
script_export_mode=1
script_encryption_key=""
[preset.3.options]
custom_template/debug=""
custom_template/release=""
variant/export_type=0
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=1
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 )

84
hud/button-down.svg Normal file
View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="94"
height="94"
viewBox="0 0 24.870833 24.870834"
version="1.1"
id="svg5"
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20, custom)"
sodipodi:docname="button-down.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:document-units="mm"
showgrid="false"
units="px"
showguides="true"
inkscape:zoom="2"
inkscape:cx="167"
inkscape:cy="168.25"
inkscape:window-width="1920"
inkscape:window-height="1049"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer2" />
<defs
id="defs2" />
<g
inkscape:label="Fond"
inkscape:groupmode="layer"
id="layer1"
style="display:none"
sodipodi:insensitive="true">
<rect
style="fill:#483e37;stroke-width:1.00012;stroke-linecap:round;stroke-linejoin:round"
id="rect846"
width="24.870766"
height="24.870781"
x="0"
y="0" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Pad">
<circle
style="fill:none;fill-opacity:1;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path5748"
cx="12.435356"
cy="4.4979081"
r="3.5718751" />
<circle
style="fill:#e1e1e1;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
id="circle5981"
cx="12.435356"
cy="20.372906"
r="3.5718751" />
<circle
style="fill:none;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="circle5983"
cx="-20.372856"
cy="-12.435405"
r="3.5718751"
transform="scale(-1)" />
<circle
style="fill:none;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="circle5985"
cx="-4.4978595"
cy="-12.435405"
r="3.5718751"
transform="scale(-1)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,35 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/button-down.svg-19035486a9e6750d8ab8f48ae9262019.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://hud/button-down.svg"
dest_files=[ "res://.import/button-down.svg-19035486a9e6750d8ab8f48ae9262019.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

84
hud/button-left.svg Normal file
View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="94"
height="94"
viewBox="0 0 24.870833 24.870834"
version="1.1"
id="svg5"
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20, custom)"
sodipodi:docname="button-left.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:document-units="mm"
showgrid="false"
units="px"
showguides="true"
inkscape:zoom="2"
inkscape:cx="167"
inkscape:cy="168.25"
inkscape:window-width="1920"
inkscape:window-height="1049"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer2" />
<defs
id="defs2" />
<g
inkscape:label="Fond"
inkscape:groupmode="layer"
id="layer1"
style="display:none"
sodipodi:insensitive="true">
<rect
style="fill:#483e37;stroke-width:1.00012;stroke-linecap:round;stroke-linejoin:round"
id="rect846"
width="24.870766"
height="24.870781"
x="0"
y="0" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Pad">
<circle
style="fill:none;fill-opacity:1;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path5748"
cx="12.435356"
cy="4.4979081"
r="3.5718751" />
<circle
style="fill:none;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
id="circle5981"
cx="12.435356"
cy="20.372906"
r="3.5718751" />
<circle
style="fill:none;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="circle5983"
cx="-20.372856"
cy="-12.435405"
r="3.5718751"
transform="scale(-1)" />
<circle
style="fill:#e1e1e1;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
id="circle5985"
cx="-4.4978595"
cy="-12.435405"
r="3.5718751"
transform="scale(-1)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,35 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/button-left.svg-b493beadc1692f5d95f7116825ca3d31.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://hud/button-left.svg"
dest_files=[ "res://.import/button-left.svg-b493beadc1692f5d95f7116825ca3d31.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

84
hud/button-right.svg Normal file
View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="94"
height="94"
viewBox="0 0 24.870833 24.870834"
version="1.1"
id="svg5"
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20, custom)"
sodipodi:docname="button-right.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:document-units="mm"
showgrid="false"
units="px"
showguides="true"
inkscape:zoom="2"
inkscape:cx="167"
inkscape:cy="168.25"
inkscape:window-width="1920"
inkscape:window-height="1049"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer2" />
<defs
id="defs2" />
<g
inkscape:label="Fond"
inkscape:groupmode="layer"
id="layer1"
style="display:none"
sodipodi:insensitive="true">
<rect
style="fill:#483e37;stroke-width:1.00012;stroke-linecap:round;stroke-linejoin:round"
id="rect846"
width="24.870766"
height="24.870781"
x="0"
y="0" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Pad">
<circle
style="fill:none;fill-opacity:1;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path5748"
cx="12.435356"
cy="4.4979081"
r="3.5718751" />
<circle
style="fill:none;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
id="circle5981"
cx="12.435356"
cy="20.372906"
r="3.5718751" />
<circle
style="fill:#e1e1e1;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
id="circle5983"
cx="-20.372856"
cy="-12.435405"
r="3.5718751"
transform="scale(-1)" />
<circle
style="fill:none;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
id="circle5985"
cx="-4.4978595"
cy="-12.435405"
r="3.5718751"
transform="scale(-1)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,35 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/button-right.svg-a7ae82ec2bd2de27e96aafd5ec8a0173.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://hud/button-right.svg"
dest_files=[ "res://.import/button-right.svg-a7ae82ec2bd2de27e96aafd5ec8a0173.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

84
hud/button-up.svg Normal file
View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="94"
height="94"
viewBox="0 0 24.870833 24.870834"
version="1.1"
id="svg5"
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20, custom)"
sodipodi:docname="button-up.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:document-units="mm"
showgrid="false"
units="px"
showguides="true"
inkscape:zoom="2"
inkscape:cx="167"
inkscape:cy="168.25"
inkscape:window-width="1920"
inkscape:window-height="1049"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer2" />
<defs
id="defs2" />
<g
inkscape:label="Fond"
inkscape:groupmode="layer"
id="layer1"
style="display:none"
sodipodi:insensitive="true">
<rect
style="fill:#483e37;stroke-width:1.00012;stroke-linecap:round;stroke-linejoin:round"
id="rect846"
width="24.870766"
height="24.870781"
x="0"
y="0" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Pad">
<circle
style="fill:#e1e1e1;fill-opacity:1;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path5748"
cx="12.435356"
cy="4.4979081"
r="3.5718751" />
<circle
style="fill:none;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="circle5981"
cx="12.435356"
cy="20.372906"
r="3.5718751" />
<circle
style="fill:none;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="circle5983"
cx="-20.372856"
cy="-12.435405"
r="3.5718751"
transform="scale(-1)" />
<circle
style="fill:none;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="circle5985"
cx="-4.4978595"
cy="-12.435405"
r="3.5718751"
transform="scale(-1)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

35
hud/button-up.svg.import Normal file
View File

@ -0,0 +1,35 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/button-up.svg-7810841ec24551e68b863549473e8b67.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://hud/button-up.svg"
dest_files=[ "res://.import/button-up.svg-7810841ec24551e68b863549473e8b67.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

141
hud/joypad.svg Normal file
View File

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="360"
height="210"
viewBox="0 0 95.249997 55.562501"
version="1.1"
id="svg5"
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20, custom)"
sodipodi:docname="joypad.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:document-units="mm"
showgrid="false"
units="px"
showguides="true"
inkscape:zoom="2"
inkscape:cx="167"
inkscape:cy="168.25"
inkscape:window-width="1920"
inkscape:window-height="1049"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs2" />
<g
inkscape:label="Fond"
inkscape:groupmode="layer"
id="layer1"
sodipodi:insensitive="true"
style="display:none">
<rect
style="fill:#483e37;stroke-width:1.00012;stroke-linecap:round;stroke-linejoin:round"
id="rect846"
width="95.25"
height="55.562477"
x="0"
y="0" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Pad"
sodipodi:insensitive="true">
<path
style="fill:none;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 10.583333,52.916655 C -2.6920977,43.784228 3.0225601,15.741441 14.816667,4.7624929 22.822381,-2.6899015 36.687466,4.2333253 47.625,4.2333253 c 10.937534,0 24.802619,-6.9232268 32.808333,0.5291676 11.794107,10.9789481 17.508765,39.0217351 4.233334,48.1541621 -6.304422,4.336935 -13.181131,-8.334483 -20.6375,-10.054167 -10.656369,-2.457709 -22.151964,-2.457709 -32.808333,0 -7.456369,1.719684 -14.333079,14.391102 -20.637501,10.054167 z"
id="path980"
sodipodi:nodetypes="aaaaaaaa" />
<path
style="fill:none;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 20.108333,12.69999 h 7.9375 v 7.9375 h 7.9375 v 7.9375 h -7.9375 v 7.9375 h -7.9375 v -7.9375 h -7.9375 v -7.9375 h 7.9375 z"
id="path3934"
sodipodi:nodetypes="ccccccccccccc" />
<circle
style="fill:none;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path5748"
cx="72.231239"
cy="16.668736"
r="3.5718751" />
<circle
style="fill:none;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="circle5981"
cx="72.231239"
cy="32.543751"
r="3.5718751" />
<circle
style="fill:none;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="circle5983"
cx="-80.168747"
cy="-24.606243"
r="3.5718751"
transform="scale(-1)" />
<circle
style="fill:none;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="circle5985"
cx="-64.293732"
cy="-24.606243"
r="3.5718751"
transform="scale(-1)" />
</g>
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="Lines"
sodipodi:insensitive="true">
<path
style="fill:none;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 24.077083,16.66875 H 0.26458333"
id="path7763"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 16.139583,24.60625 H 0.26458333"
id="path7765"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 24.077083,32.54375 H 0.26458333"
id="path7767"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 32.014583,24.60625 v 15.875 H 0.26458333"
id="path7769"
sodipodi:nodetypes="ccc" />
<path
style="fill:none;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 72.23125,16.66875 H 94.985417"
id="path7771"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 80.16875,24.60625 H 94.985417"
id="path7773"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 72.23125,32.54375 H 94.985417"
id="path7775"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#e1e1e1;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 64.29375,24.60625 v 15.875 h 30.691667"
id="path7777"
sodipodi:nodetypes="ccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.0 KiB

35
hud/joypad.svg.import Normal file
View File

@ -0,0 +1,35 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/joypad.svg-b01353fcdd771ea7c0728dcff1aff6a9.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://hud/joypad.svg"
dest_files=[ "res://.import/joypad.svg-b01353fcdd771ea7c0728dcff1aff6a9.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

101
hud/map_viewer.gd Normal file
View File

@ -0,0 +1,101 @@
extends Control
# Member variables
export var show_unvisited: bool = false
export var ground_visited: Color = Color(0x359235ff)
export var ground_unvisited: Color = Color(0x359235ce)
export var ground_unseen: Color = Color(0x80ced3ce)
export var wall_visited: Color = Color(0x000000ff)
export var wall_unvisited: Color = Color(0x000000ce)
export var player_color: Color = Color(0x2b40efff)
export var chest_color: Color = Color(0xef2b3dff)
export var entrance_color: Color = Color(0xe9ed57ff)
export var exit_color: Color = Color(0xde57edff)
var level: Maze = null
var player: MazePlayer = null
const cell_size = 15
const cell_dim = Vector2(cell_size, cell_size)
func init(lvl: Maze, pl: MazePlayer):
level = lvl
player = pl
update()
# Drawing function
func _draw():
for j in range(level.height):
for i in range(level.width):
drawGround(level.at(i, j), i, j)
drawFeature(level.at(i, j), i, j)
for j in range(level.height):
for i in range(level.width):
drawWalls(level.at(i, j), i, j)
drawPlayer()
func drawGround(c: Cell, i, j):
var color
if c.visited:
color = ground_visited
elif show_unvisited:
color = ground_unvisited
else:
color = ground_unseen
draw_rect(
Rect2(
cell_size * Vector2(i, j),
cell_dim),
color)
func drawFeature(c: Cell, i, j):
if c.visited or show_unvisited:
var orig = cell_size * Vector2(i, j)
match c.feature:
Cell.Feature.ENTRANCE:
draw_rect(Rect2(orig, cell_dim), entrance_color)
Cell.Feature.EXIT:
draw_rect(Rect2(orig, cell_dim), exit_color)
Cell.Feature.CHEST:
draw_circle(orig + cell_dim * 0.5, cell_size/2, chest_color)
_:
pass
func drawWalls(c: Cell, i, j):
drawWall(c, Direction.NORTH, i, j)
drawWall(c, Direction.WEST, i, j)
drawWall(c, Direction.SOUTH, i, j)
drawWall(c, Direction.EAST, i, j)
func drawWall(c: Cell, dir, i, j):
var color
if c.visited:
color = wall_visited
else:
color = wall_unvisited
if (c.visited or show_unvisited) && (c.get_edge(dir) == Cell.Edge.WALL):
var orig = cell_size * Vector2(i, j)
var from = orig + cell_size * Direction.edge_from(dir)
var to = orig + cell_size * Direction.edge_to(dir)
draw_line(from, to, color, 2)
func drawPlayer():
var orig = cell_size * player.position
var points = [Vector2(0, 0), Vector2(0, 0), Vector2(0, 0)]
match player.forward_dir:
Direction.NORTH:
points[0] = orig + Vector2(cell_size / 2, 2)
points[1] = orig + Vector2(cell_size - 2, cell_size - 2)
points[2] = orig + Vector2(2, cell_size - 2)
Direction.SOUTH:
points[0] = orig + Vector2(cell_size / 2, cell_size - 2)
points[1] = orig + Vector2(cell_size - 2, 2)
points[2] = orig + Vector2(2, 2)
Direction.EAST:
points[0] = orig + Vector2(cell_size - 2, cell_size / 2)
points[1] = orig + Vector2(2, 2)
points[2] = orig + Vector2(2, cell_size - 2)
Direction.WEST:
points[0] = orig + Vector2(2, cell_size / 2)
points[1] = orig + Vector2(cell_size - 2, 2)
points[2] = orig + Vector2(cell_size - 2, cell_size - 2)
draw_colored_polygon(PoolVector2Array(points), player_color)

13
hud/map_viewer.tscn Normal file
View File

@ -0,0 +1,13 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://hud/map_viewer.gd" type="Script" id=1]
[node name="MapViewer" type="Control"]
rect_min_size = Vector2( 600, 600 )
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": true
}
ground_unvisited = Color( 0.129412, 0.34902, 0.129412, 1 )
ground_unseen = Color( 0.411765, 0.415686, 0.411765, 1 )
player_color = Color( 0.0666667, 0.0980392, 0.352941, 1 )

BIN
icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

35
icon.png.import Normal file
View 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

69
main.gd Normal file
View File

@ -0,0 +1,69 @@
extends Node
const ExplorationScreen = preload("res://screen/exploration_screen.tscn")
const StartScreen = preload("res://screen/start_screen.tscn")
const MapScreen = preload("res://screen/map_screen.tscn")
const EndScreen = preload("res://screen/end_screen.tscn")
# Member variables.
var map_width = 40
var map_height = 40
var generator = Generator.new()
var level: Maze = null
var player: MazePlayer = MazePlayer.new()
var current_screen: AbstractScreen = null
# Called when the node enters the scene tree for the first time.
func _ready():
randomize()
goToStartScreen()
func new_level():
# Generate level
level = generator.generate_map(map_width, map_height)
# Teleport player at the entrance
player.teleport_at(level.entrance)
player.turn_at(randi() % 4)
func on_next_screen(screen):
match screen:
'start':
goToStartScreen()
'exploration':
goToExplorationScreen()
'map':
goToMapScreen()
'end':
goToEndScreen()
func clean_up_screen():
if current_screen != null:
current_screen.queue_free()
func attach_screen():
current_screen.connect("next_screen", self, "on_next_screen")
add_child(current_screen)
func goToStartScreen():
clean_up_screen()
current_screen = StartScreen.instance()
new_level()
attach_screen()
func goToExplorationScreen():
clean_up_screen()
current_screen = ExplorationScreen.instance()
current_screen.init(level, player)
attach_screen()
func goToMapScreen():
clean_up_screen()
current_screen = MapScreen.instance()
current_screen.init(level, player)
attach_screen()
func goToEndScreen():
clean_up_screen()
current_screen = EndScreen.instance()
current_screen.init(level, player)
attach_screen()

6
main.tscn Normal file
View File

@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://main.gd" type="Script" id=1]
[node name="Main" type="Node"]
script = ExtResource( 1 )

150
project.godot Normal file
View File

@ -0,0 +1,150 @@
; 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
_global_script_classes=[ {
"base": "Node",
"class": "AbstractScreen",
"language": "GDScript",
"path": "res://screen/abstract_screen.gd"
}, {
"base": "Reference",
"class": "Cell",
"language": "GDScript",
"path": "res://tools/cell.gd"
}, {
"base": "Object",
"class": "Direction",
"language": "GDScript",
"path": "res://tools/direction.gd"
}, {
"base": "Reference",
"class": "Generator",
"language": "GDScript",
"path": "res://tools/generator.gd"
}, {
"base": "Reference",
"class": "Maze",
"language": "GDScript",
"path": "res://tools/maze.gd"
}, {
"base": "Reference",
"class": "MazePlayer",
"language": "GDScript",
"path": "res://tools/maze_player.gd"
}, {
"base": "Spatial",
"class": "Player",
"language": "GDScript",
"path": "res://entity/player.gd"
} ]
_global_script_class_icons={
"AbstractScreen": "",
"Cell": "",
"Direction": "",
"Generator": "",
"Maze": "",
"MazePlayer": "",
"Player": ""
}
[application]
config/name="Ygdra"
run/main_scene="res://main.tscn"
config/icon="res://icon.png"
[input]
ui_accept={
"deadzone": 0.5,
"events": [ Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":0,"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":32,"physical_scancode":0,"unicode":0,"echo":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":16777221,"physical_scancode":0,"unicode":0,"echo":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":16777222,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
]
}
ui_select={
"deadzone": 0.5,
"events": [ ]
}
ui_cancel={
"deadzone": 0.5,
"events": [ Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":1,"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":16777220,"physical_scancode":0,"unicode":0,"echo":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":16777224,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
]
}
ui_focus_next={
"deadzone": 0.5,
"events": [ ]
}
ui_focus_prev={
"deadzone": 0.5,
"events": [ ]
}
ui_page_up={
"deadzone": 0.5,
"events": [ ]
}
ui_page_down={
"deadzone": 0.5,
"events": [ ]
}
ui_home={
"deadzone": 0.5,
"events": [ ]
}
ui_end={
"deadzone": 0.5,
"events": [ ]
}
ui_next={
"deadzone": 0.5,
"events": [ Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":5,"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":16777236,"physical_scancode":0,"unicode":0,"echo":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":16777218,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
]
}
ui_prev={
"deadzone": 0.5,
"events": [ Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":4,"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":16777235,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":true,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777218,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
]
}
ui_menu={
"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":16777217,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":3,"pressure":0.0,"pressed":false,"script":null)
]
}
ui_info={
"deadzone": 0.5,
"events": [ Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":2,"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":16777244,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
]
}
[layer_names]
3d_physics/layer_1="wall"
3d_physics/layer_2="ground"
3d_physics/layer_3="player"
[physics]
common/enable_pause_aware_picking=true
[rendering]
quality/driver/driver_name="GLES2"
vram_compression/import_etc=true
vram_compression/import_etc2=false
environment/default_environment="res://default_env.tres"

View File

@ -0,0 +1,5 @@
class_name AbstractScreen
extends Node
# Abstract screen. Only for definition of signals
signal next_screen(screen_name)

25
screen/end_screen.gd Normal file
View File

@ -0,0 +1,25 @@
extends AbstractScreen
# Initialization
func init(lvl: Maze, pl: MazePlayer):
var has_won = lvl.at(pl.position.x, pl.position.y).feature == Cell.Feature.EXIT
if has_won:
$EndCondition.text = "Left the labyrinth."
else:
$EndCondition.text = "Rescued after using an emergency flare."
$NbChests.text = "Found " + str(pl.nb_chests_found) + " chests."
if has_won:
$NbSteps.text = "Reached the exit in " + str(pl.nb_steps) + " steps."
else:
$NbSteps.text = "Gave up after " + str(pl.nb_steps) + " steps."
$MapViewer.init(lvl, pl)
func _process(_delta):
if Input.is_action_just_pressed("ui_accept"):
emit_signal("next_screen", "start")
if Input.is_action_just_pressed("ui_cancel"):
emit_signal("next_screen", "start")
if Input.is_action_just_pressed("ui_menu"):
emit_signal("next_screen", "start")
if Input.is_action_just_pressed("ui_info"):
emit_signal("next_screen", "start")

64
screen/end_screen.tscn Normal file
View File

@ -0,0 +1,64 @@
[gd_scene load_steps=5 format=2]
[ext_resource path="res://screen/end_screen.gd" type="Script" id=1]
[ext_resource path="res://hud/map_viewer.tscn" type="PackedScene" id=2]
[ext_resource path="res://LibertinusSans-Regular.otf" type="DynamicFontData" id=3]
[sub_resource type="DynamicFont" id=1]
size = 30
font_data = ExtResource( 3 )
[node name="EndScreen" type="Node"]
script = ExtResource( 1 )
[node name="ColorRect" type="ColorRect" parent="."]
margin_right = 1024.0
margin_bottom = 600.0
color = Color( 0.211765, 0.294118, 0.231373, 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="MapViewer" parent="." instance=ExtResource( 2 )]
margin_left = 424.0
margin_right = 1024.0
margin_bottom = 600.0
show_unvisited = true
[node name="EndCondition" type="Label" parent="."]
margin_right = 384.0
margin_bottom = 64.0
custom_fonts/font = SubResource( 1 )
text = "EndCondition"
align = 1
valign = 1
autowrap = true
__meta__ = {
"_edit_use_anchors_": false
}
[node name="NbSteps" type="Label" parent="."]
margin_top = 128.0
margin_right = 384.0
margin_bottom = 192.0
custom_fonts/font = SubResource( 1 )
text = "NbSteps"
align = 1
valign = 1
autowrap = true
__meta__ = {
"_edit_use_anchors_": false
}
[node name="NbChests" type="Label" parent="."]
margin_top = 256.0
margin_right = 384.0
margin_bottom = 320.0
custom_fonts/font = SubResource( 1 )
text = "NbChests"
align = 1
valign = 1
autowrap = true
__meta__ = {
"_edit_use_anchors_": false
}

View File

@ -0,0 +1,101 @@
extends AbstractScreen
const Wall = preload("res://entity/wall.tscn")
const Chest = preload("res://entity/chest.tscn")
# Member variables
var level: Maze = null
var player: MazePlayer = null
# Dictionary of feature to their 3D representations
var features = {}
# Initialization
func init(lvl: Maze, pl: MazePlayer):
level = lvl
player = pl
func _ready():
# Create walls
for j in range(level.height):
for i in range(level.width):
place_walls(level.at(i, j), i, j)
place_feature(level.at(i, j), i, j)
# Place Entrance
$Root3D/Entrance.transform.origin = map_pos_to_3D_pos(level.entrance.x, level.entrance.y)
# Place Exit
$Root3D/Exit.transform.origin = map_pos_to_3D_pos(level.exit.x, level.exit.y)
# Place player
$Root3D/Player.teleport_at(map_pos_to_3D_pos(player.position.x, player.position.y))
$Root3D/Player.turn_at(player.forward_dir)
# Update the level state
updateLevelState()
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(_delta):
if (not $Root3D/Player.in_movement()) and (level.at(player.position.x, player.position.y).feature == Cell.Feature.EXIT):
emit_signal("next_screen", "end")
if Input.is_action_just_pressed("ui_menu"):
emit_signal("next_screen", "end")
if Input.is_action_just_pressed("ui_accept"):
emit_signal("next_screen", "map")
if not $Root3D/Player.in_movement():
if Input.is_action_pressed("ui_up") and player.can_move_forward(level):
player.move_forward()
$Root3D/Player.move_forward()
updateLevelState()
elif Input.is_action_pressed("ui_down") and player.can_move_backward(level):
player.move_backward()
$Root3D/Player.move_backward()
updateLevelState()
elif Input.is_action_pressed("ui_left"):
player.turn_left()
$Root3D/Player.turn_left()
updateLevelState()
elif Input.is_action_pressed("ui_right"):
player.turn_right()
$Root3D/Player.turn_right()
updateLevelState()
func map_pos_to_3D_pos(i, j):
return Vector3(-(level.width - 1) + 2 * i, 0, -(level.height - 1) + 2 * j)
func place_walls(c: Cell, i, j):
new_wall(c, Direction.NORTH, i, j)
new_wall(c, Direction.SOUTH, i, j)
new_wall(c, Direction.EAST, i, j)
new_wall(c, Direction.WEST, i, j)
func new_wall(c: Cell, dir, i, j):
# Compute position and rotation of the element
var offset = Vector3(0.9 * Direction.offset_x(dir), 0, 0.9 * Direction.offset_y(dir))
var wall_position = map_pos_to_3D_pos(i, j) + offset
var wall_angle = PI/2 * Direction.offset_x(dir)
if c.get_edge(dir) == Cell.Edge.WALL:
var wall = Wall.instance()
wall.translate_object_local(wall_position)
wall.rotate_object_local(Vector3.UP, wall_angle)
$Root3D/Walls.add_child(wall)
func place_feature(c: Cell, i, j):
if c.feature == Cell.Feature.CHEST:
new_chest(c, i, j)
func new_chest(c: Cell, i, j):
var chest = Chest.instance()
chest.translate_object_local(map_pos_to_3D_pos(i, j))
$Root3D/Chests.add_child(chest)
features[Vector2(i, j)] = chest
func updateHUD():
$HUD/NbSteps.text = "Steps: " + str(player.nb_steps)
$HUD/NbChests.text = "Chests: " + str(player.nb_chests_found)
func updateLevelState():
level.visit(player.position)
var pos = player.position
if (level.at(pos.x, pos.y).feature == Cell.Feature.CHEST):
player.open_chest()
level.at(pos.x, pos.y).feature = Cell.Feature.NONE
features.get(pos).queue_free()
features.erase(pos)
updateHUD()

View File

@ -0,0 +1,95 @@
[gd_scene load_steps=11 format=2]
[ext_resource path="res://screen/exploration_screen.gd" type="Script" id=1]
[ext_resource path="res://entity/player.tscn" type="PackedScene" id=2]
[ext_resource path="res://entity/ground.tscn" type="PackedScene" id=3]
[ext_resource path="res://LibertinusSans-Regular.otf" type="DynamicFontData" id=4]
[ext_resource path="res://entity/exit.tscn" type="PackedScene" id=5]
[ext_resource path="res://entity/entrance.tscn" type="PackedScene" id=6]
[ext_resource path="res://hud/button-up.svg" type="Texture" id=7]
[ext_resource path="res://hud/button-down.svg" type="Texture" id=8]
[sub_resource type="DynamicFont" id=1]
size = 24
font_data = ExtResource( 4 )
[sub_resource type="DynamicFont" id=2]
size = 24
font_data = ExtResource( 4 )
[node name="ExplorationScreen" type="Node"]
script = ExtResource( 1 )
[node name="Root3D" type="Spatial" parent="."]
[node name="Player" parent="Root3D" instance=ExtResource( 2 )]
[node name="Ground" parent="Root3D" instance=ExtResource( 3 )]
[node name="Entrance" parent="Root3D" instance=ExtResource( 6 )]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 5, 0, 5 )
[node name="Exit" parent="Root3D" instance=ExtResource( 5 )]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 5, 0, 3 )
[node name="Walls" type="Spatial" parent="Root3D"]
[node name="Chests" type="Spatial" parent="Root3D"]
[node name="HUD" type="Node" parent="."]
[node name="NbSteps" type="Label" parent="HUD"]
margin_left = 16.0
margin_top = 528.0
margin_right = 97.0
margin_bottom = 551.0
custom_fonts/font = SubResource( 1 )
text = "NbSteps"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="NbChests" type="Label" parent="HUD"]
margin_left = 16.0
margin_top = 560.0
margin_right = 97.0
margin_bottom = 583.0
custom_fonts/font = SubResource( 2 )
text = "NbChests"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Help" type="Node" parent="HUD"]
[node name="Button-Stop" type="Sprite" parent="HUD/Help"]
position = Vector2( 855.5, 568 )
scale = Vector2( 0.5, 0.5 )
texture = ExtResource( 7 )
[node name="Stop" type="Label" parent="HUD/Help"]
margin_left = 887.5
margin_top = 552.0
margin_right = 1009.5
margin_bottom = 580.0
custom_fonts/font = SubResource( 2 )
text = "Leave Game"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Button-Map" type="Sprite" parent="HUD/Help"]
position = Vector2( 856, 503.5 )
scale = Vector2( 0.5, 0.5 )
texture = ExtResource( 8 )
[node name="Map" type="Label" parent="HUD/Help"]
margin_left = 888.0
margin_top = 487.5
margin_right = 1010.0
margin_bottom = 515.5
custom_fonts/font = SubResource( 2 )
text = "Show Map"
__meta__ = {
"_edit_use_anchors_": false
}

23
screen/map_screen.gd Normal file
View File

@ -0,0 +1,23 @@
extends AbstractScreen
# Ready : set the colors of caption according to the used in MapViewer
func _ready():
$Captions/Entrance.color = $MapViewer.entrance_color
$Captions/Exit.color = $MapViewer.exit_color
$Captions/Path.color = $MapViewer.ground_visited
$Captions/Player.color = $MapViewer.player_color
$Captions/Chest.color = $MapViewer.chest_color
# Initialization
func init(lvl: Maze, pl: MazePlayer):
$MapViewer.init(lvl, pl)
func _process(_delta):
if Input.is_action_just_pressed("ui_accept"):
emit_signal("next_screen", "exploration")
if Input.is_action_just_pressed("ui_cancel"):
emit_signal("next_screen", "exploration")
if Input.is_action_just_pressed("ui_menu"):
emit_signal("next_screen", "exploration")
if Input.is_action_just_pressed("ui_info"):
emit_signal("next_screen", "exploration")

119
screen/map_screen.tscn Normal file
View File

@ -0,0 +1,119 @@
[gd_scene load_steps=5 format=2]
[ext_resource path="res://screen/map_screen.gd" type="Script" id=1]
[ext_resource path="res://hud/map_viewer.tscn" type="PackedScene" id=2]
[ext_resource path="res://LibertinusSans-Regular.otf" type="DynamicFontData" id=3]
[sub_resource type="DynamicFont" id=1]
size = 24
font_data = ExtResource( 3 )
[node name="MapScreen" type="Node2D"]
script = ExtResource( 1 )
[node name="ColorRect" type="ColorRect" parent="."]
margin_right = 1024.0
margin_bottom = 600.0
color = Color( 0.211765, 0.294118, 0.231373, 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="MapViewer" parent="." instance=ExtResource( 2 )]
margin_left = 212.0
margin_right = 812.0
margin_bottom = 600.0
[node name="Captions" type="Node" parent="."]
[node name="Entrance" type="ColorRect" parent="Captions"]
margin_left = 24.0
margin_top = 48.0
margin_right = 40.0
margin_bottom = 64.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="EntranceLbl" type="Label" parent="Captions"]
margin_left = 56.0
margin_top = 40.0
margin_right = 178.0
margin_bottom = 68.0
custom_fonts/font = SubResource( 1 )
text = "Entrance"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Exit" type="ColorRect" parent="Captions"]
margin_left = 24.0
margin_top = 88.0
margin_right = 40.0
margin_bottom = 104.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ExitLbl" type="Label" parent="Captions"]
margin_left = 56.0
margin_top = 80.0
margin_right = 178.0
margin_bottom = 108.0
custom_fonts/font = SubResource( 1 )
text = "Exit"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Path" type="ColorRect" parent="Captions"]
margin_left = 24.0
margin_top = 128.0
margin_right = 40.0
margin_bottom = 144.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="PathLbl" type="Label" parent="Captions"]
margin_left = 56.0
margin_top = 120.0
margin_right = 178.0
margin_bottom = 148.0
custom_fonts/font = SubResource( 1 )
text = "Path"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Player" type="Polygon2D" parent="Captions"]
position = Vector2( 13.3333, 8.00017 )
scale = Vector2( 0.666667, 0.999999 )
polygon = PoolVector2Array( 16, 160, 40, 168, 16, 176 )
[node name="PlayerLbl" type="Label" parent="Captions"]
margin_left = 56.0
margin_top = 160.0
margin_right = 178.0
margin_bottom = 188.0
custom_fonts/font = SubResource( 1 )
text = "Player"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Chest" type="Polygon2D" parent="Captions"]
position = Vector2( 18.6667, 74.6667 )
scale = Vector2( 0.666667, 0.666667 )
polygon = PoolVector2Array( 16, 200, 8, 208, 8, 216, 16, 224, 24, 224, 32, 216, 32, 208, 24, 200 )
[node name="ChestLbl" type="Label" parent="Captions"]
margin_left = 56.0
margin_top = 200.0
margin_right = 178.0
margin_bottom = 228.0
custom_fonts/font = SubResource( 1 )
text = "Chest"
__meta__ = {
"_edit_use_anchors_": false
}

8
screen/start_screen.gd Normal file
View File

@ -0,0 +1,8 @@
extends AbstractScreen
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
if Input.is_action_just_pressed("ui_menu"):
get_tree().notification(MainLoop.NOTIFICATION_WM_QUIT_REQUEST)
if Input.is_action_just_pressed("ui_accept"):
emit_signal("next_screen", "exploration")

231
screen/start_screen.tscn Normal file
View File

@ -0,0 +1,231 @@
[gd_scene load_steps=8 format=2]
[ext_resource path="res://LibertinusSans-Regular.otf" type="DynamicFontData" id=1]
[ext_resource path="res://screen/start_screen.gd" type="Script" id=2]
[ext_resource path="res://hud/joypad.svg" type="Texture" id=3]
[ext_resource path="res://hud/button-up.svg" type="Texture" id=4]
[ext_resource path="res://hud/button-down.svg" type="Texture" id=5]
[sub_resource type="DynamicFont" id=1]
size = 80
font_data = ExtResource( 1 )
[sub_resource type="DynamicFont" id=2]
size = 26
font_data = ExtResource( 1 )
[node name="StartScreen" type="Node"]
script = ExtResource( 2 )
[node name="ColorRect" type="ColorRect" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
color = Color( 0.211765, 0.294118, 0.231373, 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Message" type="Label" parent="."]
anchor_right = 1.0
margin_bottom = 92.0
custom_fonts/font = SubResource( 1 )
text = "Ygdra"
align = 1
autowrap = true
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Controls" type="Control" parent="."]
anchor_left = 0.5
anchor_top = 1.0
anchor_right = 0.5
anchor_bottom = 1.0
margin_left = -512.0
margin_top = -280.0
margin_right = 512.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Joypad" type="Sprite" parent="Controls"]
position = Vector2( 512, 151 )
texture = ExtResource( 3 )
[node name="Label" type="Label" parent="Controls"]
margin_left = 264.0
margin_top = 93.0
margin_right = 324.0
margin_bottom = 128.0
custom_fonts/font = SubResource( 2 )
text = "[UP]"
align = 2
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Label2" type="Label" parent="Controls"]
margin_left = 240.0
margin_top = 123.0
margin_right = 324.0
margin_bottom = 158.0
custom_fonts/font = SubResource( 2 )
text = "[LEFT]"
align = 2
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Label3" type="Label" parent="Controls"]
margin_left = 224.0
margin_top = 152.0
margin_right = 323.0
margin_bottom = 187.0
custom_fonts/font = SubResource( 2 )
text = "[DOWN]"
align = 2
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Label4" type="Label" parent="Controls"]
margin_left = 224.0
margin_top = 183.0
margin_right = 323.0
margin_bottom = 218.0
custom_fonts/font = SubResource( 2 )
text = "[RIGHT]"
align = 2
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Label5" type="Label" parent="Controls"]
margin_left = 696.0
margin_top = 93.0
margin_right = 759.0
margin_bottom = 128.0
custom_fonts/font = SubResource( 2 )
text = "[ESC]"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Label6" type="Label" parent="Controls"]
margin_left = 696.0
margin_top = 123.0
margin_right = 856.0
margin_bottom = 158.0
custom_fonts/font = SubResource( 2 )
text = "[BACKSPACE]"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Label7" type="Label" parent="Controls"]
margin_left = 696.0
margin_top = 152.0
margin_right = 795.0
margin_bottom = 187.0
custom_fonts/font = SubResource( 2 )
text = "[SPACE]"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Label8" type="Label" parent="Controls"]
margin_left = 696.0
margin_top = 183.0
margin_right = 795.0
margin_bottom = 218.0
custom_fonts/font = SubResource( 2 )
text = "[F1]"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Infos" type="Control" parent="."]
anchor_top = 0.5
anchor_right = 1.0
anchor_bottom = 0.5
margin_top = -196.0
margin_bottom = 84.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Goal" type="Label" parent="Infos"]
anchor_right = 1.0
margin_bottom = 99.0
custom_fonts/font = SubResource( 2 )
text = "You accidentally stepped on a yellow plate that teleported you into a mysterious labyrinth.
Find the purple plate to exit it.
Someone hid chests there, can you find them too ?"
align = 1
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Buttons" type="Control" parent="Infos"]
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
margin_top = -152.0
margin_bottom = -16.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Info-Start" type="Control" parent="Infos/Buttons"]
anchor_left = 0.5
anchor_right = 0.5
margin_left = -128.0
margin_right = 128.0
margin_bottom = 128.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Start" type="Label" parent="Infos/Buttons/Info-Start"]
margin_left = 96.0
margin_top = 8.0
margin_right = 221.0
margin_bottom = 43.0
custom_fonts/font = SubResource( 2 )
text = "Start Game"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Button-Start" type="Sprite" parent="Infos/Buttons/Info-Start"]
position = Vector2( 63.5, 23.5 )
scale = Vector2( 0.5, 0.5 )
texture = ExtResource( 5 )
[node name="Info-Stop" type="Control" parent="Infos/Buttons"]
anchor_left = 0.5
anchor_top = 1.0
anchor_right = 0.5
anchor_bottom = 1.0
margin_left = -128.0
margin_top = -128.0
margin_right = 128.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Stop" type="Label" parent="Infos/Buttons/Info-Stop"]
margin_left = 96.0
margin_top = 64.0
margin_right = 217.0
margin_bottom = 99.0
custom_fonts/font = SubResource( 2 )
text = "Quit Game"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Button-Stop" type="Sprite" parent="Infos/Buttons/Info-Stop"]
position = Vector2( 63.5, 79.5 )
scale = Vector2( 0.5, 0.5 )
texture = ExtResource( 4 )

98
tools/cell.gd Normal file
View File

@ -0,0 +1,98 @@
class_name Cell
extends Reference
# Abstract cell of labyrinth
# Type of floor
enum Floor { UNKNOWN, PATH, WALL }
# Edge kind
enum Edge { WALL, NONE, DOOR }
# Feature kind
enum Feature { NONE, EVENT, ENTRANCE, EXIT, CHEST, MINE_POINT, TAKE_POINT, CHOP_POINT, HARVEST_POINT }
###
# A cell has :
# - a kind of floor indicating if it is a path, a wall, ...
var floor_kind = Floor.UNKNOWN
# - a list of edges indicating to which adjacent cell it is connected
var edges = [Edge.WALL, Edge.WALL, Edge.WALL, Edge.WALL]
# - an optional feature : entrance, exit, ...
var feature = Feature.NONE
# - a flag indicating if the cell was visited by the player
var visited = false
###
# Edge-related functions
# Set an edge
func set_edge(dir, val):
edges[dir] = val
# Get an edge
func get_edge(dir):
return edges[dir]
# Deadend
func is_deadend():
# if there are 3 walls among the edges, the cell is a deadend
var count = 0
for e in edges:
if e == Edge.WALL:
count += 1
return count == 3
# Utilities for labyrinth-building (transformations)
# Identity : do nothing
func identity():
pass
# Horizontal flip : exchange the EAST/WEST edges
func horizontal_flip():
var tmp = edges[Direction.WEST]
edges[Direction.WEST] = edges[Direction.EAST]
edges[Direction.EAST] = tmp
# Vertical flip : exchange the NORTH/SOUTH edges
func vertical_flip():
var tmp = edges[Direction.SOUTH]
edges[Direction.SOUTH] = edges[Direction.NORTH]
edges[Direction.NORTH] = tmp
# Rotation 180° = horizontal flip + vertical flip
func rotate_180():
self.horizontal_flip()
self.vertical_flip()
# Rotation 90° in trigonometric direction (counter-clockwise)
func rotate_90():
var tmp = edges[Direction.NORTH]
edges[Direction.NORTH] = edges[Direction.EAST]
edges[Direction.EAST] = edges[Direction.SOUTH]
edges[Direction.SOUTH] = edges[Direction.WEST]
edges[Direction.WEST] = tmp
# Rotation 270° in trigonometric direction (counter-clockwise), or 90° clockwise
func rotate_270():
var tmp = edges[Direction.NORTH]
edges[Direction.NORTH] = edges[Direction.WEST]
edges[Direction.WEST] = edges[Direction.SOUTH]
edges[Direction.SOUTH] = edges[Direction.EAST]
edges[Direction.EAST] = tmp
# Transposition (mirror -45°) : exchange NORTH/WEST, SOUTH/EAST
func transpose():
var tmp = edges[Direction.NORTH]
edges[Direction.NORTH] = edges[Direction.WEST]
edges[Direction.WEST] = tmp
tmp = edges[Direction.SOUTH]
edges[Direction.SOUTH] = edges[Direction.EAST]
edges[Direction.EAST] = tmp
# Anti-transposition (mirror 45°): exchange NORTH/EAST, SOUTH/WEST
func antitranspose():
var tmp = edges[Direction.NORTH]
edges[Direction.NORTH] = edges[Direction.EAST]
edges[Direction.EAST] = tmp
tmp = edges[Direction.SOUTH]
edges[Direction.SOUTH] = edges[Direction.WEST]
edges[Direction.WEST] = tmp

105
tools/direction.gd Normal file
View File

@ -0,0 +1,105 @@
class_name Direction
extends Object
# Direction enum, used to refer to the cell edges
enum { NORTH = 0, SOUTH = 1, EAST = 2, WEST = 3 }
# Get the opposite direction
static func opposite(d):
match d:
NORTH:
return SOUTH
SOUTH:
return NORTH
EAST:
return WEST
WEST:
return EAST
# Get the offset (X)
static func offset_x(d):
match d:
NORTH:
return 0
SOUTH:
return 0
EAST:
return 1
WEST:
return -1
# Get the offset (Y 2D, Z 3D)
static func offset_y(d):
match d:
NORTH:
return -1
SOUTH:
return 1
EAST:
return 0
WEST:
return 0
# Get the offset as a vector
static func offset(d):
return Vector2(offset_x(d), offset_y(d))
# Edge offset (from), as unit vectors
static func edge_from(d):
match d:
NORTH:
return Vector2(0, 0)
SOUTH:
return Vector2(0, 1)
EAST:
return Vector2(1, 0)
WEST:
return Vector2(0, 0)
static func edge_to(d):
match d:
NORTH:
return Vector2(1, 0)
SOUTH:
return Vector2(1, 1)
EAST:
return Vector2(1, 1)
WEST:
return Vector2(0, 1)
# Rotate left
static func rotate_left(d):
match d:
NORTH:
return WEST
SOUTH:
return EAST
EAST:
return NORTH
WEST:
return SOUTH
# Rotate right
static func rotate_right(d):
match d:
NORTH:
return EAST
SOUTH:
return WEST
EAST:
return SOUTH
WEST:
return NORTH
# To string
static func string_of(d):
match d:
NORTH:
return "NORTH"
SOUTH:
return "SOUTH"
EAST:
return "EAST"
WEST:
return "WEST"

118
tools/generator.gd Normal file
View File

@ -0,0 +1,118 @@
class_name Generator
extends Reference
# Maze carver position
class MazeCarverPosition:
var x: int = 0
var y: int = 0
var available_directions: Array = [Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST]
func _init(pos_x: int, pos_y: int):
x = pos_x
y = pos_y
available_directions.shuffle()
func has_next_direction():
return not available_directions.empty()
func next_direction():
return available_directions.pop_back()
# Generate a new map
# Each map is a array indicating the features of the map
func generate_map(width: int, height: int):
var maze = null
# A correct maze needs at least two events to place the entrance and exit
var events = []
while events.size() < 2:
maze = Maze.new(width, height)
var start_x = randi() % width
var start_y = randi() % height
carve_maze(maze, start_x, start_y, true)
add_events(maze)
events = maze.events
# Shuffle the event list
maze.events.shuffle()
# Set the entrance and exit
set_entrance(maze)
set_exit(maze)
# Set the chests
set_chests(maze)
return maze
# Carve a maze (iterative)
func carve_maze(maze: Maze, start_x: int, start_y: int, loop: bool):
# Starting position
var start_pos: MazeCarverPosition = MazeCarverPosition.new(start_x, start_y)
# Position pile
var carver = [start_pos]
# While there is a pos in carver
while not carver.empty():
var pos: MazeCarverPosition = carver.back()
# Set the current cell floor kind to PATH
maze.at(pos.x, pos.y).floor_kind = Cell.Floor.PATH
# If there are available directions, pick the first, and continue from there
if pos.has_next_direction():
# Get the next direction
var dir = pos.next_direction()
# Position of next cell
var nx = pos.x + Direction.offset_x(dir)
var ny = pos.y + Direction.offset_y(dir)
# if the next cell is inside the maze, and has an unknown floor kind,
# remove the wall between the cells, and continue from next cell.
if maze.is_inside(nx, ny) and (maze.at(nx, ny).floor_kind == Cell.Floor.UNKNOWN):
maze.at(pos.x, pos.y).set_edge(dir, Cell.Edge.NONE)
maze.at(nx, ny).set_edge(Direction.opposite(dir), Cell.Edge.NONE)
# Push the new position into the carver
var new_pos: MazeCarverPosition = MazeCarverPosition.new(nx, ny)
carver.push_back(new_pos)
# if the next cell is inside the maze and has a path floor kind,
# if the loop is true and at a 1/20 chance, remove the wall,
# but don't continue on the next cell
elif maze.is_inside(nx, ny) and (maze.at(nx, ny).floor_kind == Cell.Floor.PATH) and loop and (randi() % 20 < 1):
maze.at(pos.x, pos.y).set_edge(dir, Cell.Edge.NONE)
maze.at(nx, ny).set_edge(Direction.opposite(dir), Cell.Edge.NONE)
else:
# do nothing
pass
else:
# No new available position : pop pos from carver
carver.pop_back()
# Add events at the deadends
func add_events(maze: Maze):
for j in range(maze.height):
for i in range(maze.width):
if maze.at(i, j).is_deadend() and (maze.at(i, j).feature == Cell.Feature.NONE):
maze.at(i, j).feature = Cell.Feature.EVENT
maze.events.push_back(Vector2(i, j))
# Choose an event to set as the entrance
func set_entrance(maze: Maze):
var pos: Vector2 = maze.events.pop_back()
maze.at(pos.x, pos.y).feature = Cell.Feature.ENTRANCE
maze.entrance = pos
# Set the exit on the event that is farthest from the entrance
func set_exit(maze: Maze):
var distance = 0
var exit = maze.entrance
for e in maze.events:
var d = maze.entrance.distance_squared_to(e)
if d > distance:
distance = d
exit = e
maze.at(exit.x, exit.y).feature = Cell.Feature.EXIT
maze.exit = exit
# Set chests on a few events
func set_chests(maze: Maze):
var max_nb_chests = sqrt(maze.width * maze.height)
var count = 0
for e in maze.events:
if maze.at(e.x, e.y).feature == Cell.Feature.EVENT:
count += 1
maze.at(e.x, e.y).feature = Cell.Feature.CHEST
if count >= max_nb_chests:
break
maze.nb_chests = count

154
tools/maze.gd Normal file
View File

@ -0,0 +1,154 @@
class_name Maze
extends Reference
# Represents an area of cell
var width: int = 0
var height: int = 0
var cells = []
var events = []
var entrance = Vector2()
var exit = Vector2()
var nb_chests: int = 0
# For submazes, as they modify their parent maze
var parent: Maze = null # Submaze parent maze
var offset_x = 0
var offset_y = 0
# Initialize a maze
func _init(w: int, h: int):
assert(w > 0)
assert(h > 0)
width = w
height = h
cells.clear()
cells.resize(w * h)
for i in range(w * h):
cells[i] = Cell.new()
# Initialize a submaze from a parent maze.
func init_from(w: int, h: int, that: Maze, x: int, y: int):
assert(w > 0)
assert(h > 0)
width = w
height = h
parent = that
offset_x = x
offset_y = y
# Get the index for the cell at position (x,y)
func index(x: int, y: int):
return x + y * width
# Get the cell at the position (x,y)
func at(x: int, y: int):
if parent == null:
return cells[index(x, y)]
else:
parent.at(x + offset_x, y + offset_y)
# Check if a position is inside the area
func is_inside(x: int, y: int):
return (x >= 0) and (x < width) and (y >= 0) and (y < height)
# Get a submaze of this maze.
# The submaze if a view of this maze, so a modification of the submaze cells modify this maze.
func submaze(x: int, y: int, w: int, h: int):
assert(x > 0)
assert(y > 0)
assert((x + w) <= width)
assert((y + h) <= height)
var ret = load("res://tools/maze.gd").new()
ret.init_from(w, h, self, x, y)
return ret
# Transformations
# Identity : do nothing
func identity(_x: int = 0, _y: int = 0, _w: int = width, _h: int = height):
pass
# Horizontal flip
func horizontal_flip(x: int = 0, y: int = 0, w: int = width, h: int = height):
if parent == null:
for j in range(0, h):
for i in range(0, w/2):
var idx_cell = index(x + i, y + j)
var idx_other = index(x + w - 1 - i, y + j)
var cell = cells[idx_cell]
cells[idx_cell] = cells[idx_other]
cells[idx_other] = cell
for j in range(0, h):
for i in range(0, w):
var idx_cell = index(x + i, y + j)
cells[idx_cell].horizontal_flip()
else:
parent.horizontal_flip(offset_x + x, offset_y + y, w, h)
# Vertical flip
func vertical_flip(x: int = 0, y: int = 0, w: int = width, h: int = height):
if parent == null:
for j in range(0, h/2):
for i in range(0, w):
var idx_cell = index(x + i, y + j)
var idx_other = index(x + i, y + h - 1 - j)
var cell = cells[idx_cell]
cells[idx_cell] = cells[idx_other]
cells[idx_other] = cell
for j in range(0, h):
for i in range(0, w):
var idx_cell = index(x + i, y + j)
cells[idx_cell].vertical_flip()
else:
parent.vertical_flip(offset_x + x, offset_y + y, w, h)
# Rotation 180° = horizontal flip + vertical flip
func rotate_180(x: int = 0, y: int = 0, w: int = width, h: int = height):
self.horizontal_flip(x, y, w, h)
self.vertical_flip(x, y, w, h)
# Rotation 90° in trigonometric direction (counter-clockwise)
func rotate_90():
# TODO
pass
# Rotation 270° in trigonometric direction (counter-clockwise), or 90° clockwise
func rotate_270():
# TODO
pass
# Transposition (mirror -45°)
func transpose(x: int = 0, y: int = 0, w: int = width, h: int = height):
if parent == null:
for j in range(0, h):
for i in range(j + 1, w):
var idx_cell = index(x + i, y + j)
var idx_other = index(y + j, x + i)
var cell = cells[idx_cell]
cells[idx_cell] = cells[idx_other]
cells[idx_other] = cell
for j in range(0, h):
for i in range(0, w):
var idx_cell = index(x + i, y + j)
cells[idx_cell].transpose()
else:
parent.transpose(offset_x + x, offset_y + y, w, h)
# Anti-transposition (mirror 45°)
func antitranspose(x: int = 0, y: int = 0, w: int = width, h: int = height):
if parent == null:
for j in range(0, h):
for i in range(0, w - 1 - j):
var idx_cell = index(x + i, y + j)
var idx_other = index(y + h - 1 - j, x + w - 1 - i)
var cell = cells[idx_cell]
cells[idx_cell] = cells[idx_other]
cells[idx_other] = cell
for j in range(0, h):
for i in range(0, w):
var idx_cell = index(x + i, y + j)
cells[idx_cell].antitranspose()
else:
parent.antitranspose(offset_x + x, offset_y + y, w, h)
# Player-interaction functions
func visit(pos: Vector2):
at(pos.x, pos.y).visited = true

40
tools/maze_player.gd Normal file
View File

@ -0,0 +1,40 @@
class_name MazePlayer
extends Reference
# Player in maze coordinates
var position = Vector2.ZERO
var forward_dir = Direction.NORTH
var nb_steps = 0
var nb_chests_found = 0
func teleport_at(pos: Vector2):
position = pos
func turn_at(dir):
forward_dir = dir
func move_forward():
position += Direction.offset(forward_dir)
nb_steps += 1
func move_backward():
position += Direction.offset(Direction.opposite(forward_dir))
nb_steps += 1
func turn_left():
forward_dir = Direction.rotate_left(forward_dir)
func turn_right():
forward_dir = Direction.rotate_right(forward_dir)
# Check if a player can move forward
func can_move_forward(level: Maze):
return level.at(position.x, position.y).get_edge(forward_dir) != Cell.Edge.WALL
# Check if a player can move backward
func can_move_backward(level: Maze):
return level.at(position.x, position.y).get_edge(Direction.opposite(forward_dir)) != Cell.Edge.WALL
# Find a chest
func open_chest():
nb_chests_found += 1