diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..0f8f149 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,17 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto + +# Explicitly declare text files you want to always be normalized and converted +# to native line endings on checkout. +*.cpp text +*.c text +*.h text +*.gd text +*.cs text + +# Declare files that will always have CRLF line endings on checkout. +*.sln text eol=crlf + +# Denote all files that are truly binary and should not be modified. +*.png binary +*.jpg binary diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0e3fbb1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +/.import/ +/.mono/ +/bin/ +/build/ +/lib/ +/git_api.* +*.translation +export_presets.cfg diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..d0964bf --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "editor.tabSize": 4, + "editor.insertSpaces": true, + + "files.trimTrailingWhitespace": true, + "files.trimFinalNewlines": true, + "files.insertFinalNewline": true, +} diff --git a/Block.tscn b/Block.tscn new file mode 100644 index 0000000..385ac4a --- /dev/null +++ b/Block.tscn @@ -0,0 +1,16 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://gfx/block.png" type="Texture" id=1] + + +[sub_resource type="RectangleShape2D" id=3] +extents = Vector2( 8, 8 ) + +[node name="Block" type="StaticBody2D"] +position = Vector2( 0, 96 ) + +[node name="RectangleShape" type="CollisionShape2D" parent="."] +shape = SubResource( 3 ) + +[node name="Sprite" type="Sprite" parent="."] +texture = ExtResource( 1 ) diff --git a/Camera.cs b/Camera.cs new file mode 100644 index 0000000..c036915 --- /dev/null +++ b/Camera.cs @@ -0,0 +1,24 @@ +using Godot; + +public class Camera : Camera2D +{ + public int MaxDistance { get; } = 80; + public Cursor Cursor { get; private set; } + + private Vector2 _rawPosition = Vector2.Zero; + + public override void _Ready() + { + Cursor = GetViewport().GetNode("Cursor"); + } + + public override void _Process(float delta) + { + var mousePos = GetTree().Root.GetMousePosition(); + var centerPos = OS.WindowSize / 2; + var target = !Cursor.Visible ? Vector2.Zero + : ((mousePos - centerPos) / 4).Clamped(MaxDistance) * 2; + _rawPosition = _rawPosition.LinearInterpolate(target, 0.05F).Round(); + Position = _rawPosition.Round(); + } +} diff --git a/Cursor.cs b/Cursor.cs new file mode 100644 index 0000000..9f66c62 --- /dev/null +++ b/Cursor.cs @@ -0,0 +1,25 @@ +using Godot; + +public class Cursor : Node2D +{ + public override void _Ready() + { + Visible = false; + Input.SetMouseMode(Input.MouseMode.Hidden); + } + + public override void _Notification(int what) + { + switch (what) { + case MainLoop.NotificationWmMouseEnter: Visible = true; break; + case MainLoop.NotificationWmMouseExit: Visible = false; break; + } + } + + public override void _Process(float delta) + { + var viewport = (Viewport)GetViewport(); + var origin = viewport.CanvasTransform.origin; + Position = viewport.GetMousePosition() / viewport.Scale - origin; + } +} diff --git a/GameScene.tscn b/GameScene.tscn new file mode 100644 index 0000000..048609d --- /dev/null +++ b/GameScene.tscn @@ -0,0 +1,53 @@ +[gd_scene load_steps=8 format=2] + +[ext_resource path="res://gfx/player.png" type="Texture" id=1] +[ext_resource path="res://gfx/cursor.png" type="Texture" id=2] +[ext_resource path="res://Player.cs" type="Script" id=3] +[ext_resource path="res://Viewport.cs" type="Script" id=4] +[ext_resource path="res://Cursor.cs" type="Script" id=5] +[ext_resource path="res://Camera.cs" type="Script" id=6] + +[sub_resource type="CircleShape2D" id=1] +radius = 8.0 + +[node name="Game" type="ViewportContainer"] +margin_right = 384.0 +margin_bottom = 216.0 +__meta__ = { +"_edit_lock_": true, +"_edit_use_anchors_": false +} + +[node name="ViewportTexture" type="TextureRect" parent="."] +margin_right = 384.0 +margin_bottom = 216.0 +__meta__ = { +"_edit_lock_": true +} + +[node name="Viewport" type="Viewport" parent="."] +size = Vector2( 640, 360 ) +handle_input_locally = false +render_target_v_flip = true +render_target_update_mode = 3 +script = ExtResource( 4 ) + +[node name="Cursor" type="Node2D" parent="Viewport"] +script = ExtResource( 5 ) + +[node name="Sprite" type="Sprite" parent="Viewport/Cursor"] +texture = ExtResource( 2 ) + +[node name="Player" type="KinematicBody2D" parent="Viewport"] +position = Vector2( 320, 180 ) +script = ExtResource( 3 ) + +[node name="Camera2D" type="Camera2D" parent="Viewport/Player"] +current = true +script = ExtResource( 6 ) + +[node name="CircleShape" type="CollisionShape2D" parent="Viewport/Player"] +shape = SubResource( 1 ) + +[node name="Sprite" type="Sprite" parent="Viewport/Player"] +texture = ExtResource( 1 ) diff --git a/Player.cs b/Player.cs new file mode 100644 index 0000000..609e527 --- /dev/null +++ b/Player.cs @@ -0,0 +1,42 @@ +using Godot; +using System; + +public class Player : KinematicBody2D +{ + public TimeSpan JumpEarlyTime { get; } = TimeSpan.FromSeconds(0.2F); + public TimeSpan JumpCoyoteTime { get; } = TimeSpan.FromSeconds(0.2F); + + [Export] public float Speed { get; set; } = 120; + [Export] public float JumpSpeed { get; set; } = 180; + [Export] public float Gravity { get; set; } = 400; + + [Export(PropertyHint.Range, "0,1")] + public float Friction { get; set; } = 0.1F; + [Export(PropertyHint.Range, "0,1")] + public float Acceleration { get; set; } = 0.25F; + + private Vector2 _velocity = Vector2.Zero; + private DateTime? _jumpPressed = null; + private DateTime? _lastOnFloor = null; + + public override void _PhysicsProcess(float delta) + { + var moveDir = Input.GetActionStrength("move_right") - Input.GetActionStrength("move_left"); + _velocity.x = (moveDir != 0) ? Mathf.Lerp(_velocity.x, moveDir * Speed, Acceleration) + : Mathf.Lerp(_velocity.x, 0, Friction); + _velocity.y += Gravity * delta; + _velocity = MoveAndSlide(_velocity, Vector2.Up); + + if (Input.IsActionJustPressed("move_jump")) + _jumpPressed = DateTime.Now; + if (IsOnFloor()) + _lastOnFloor = DateTime.Now; + + if (((DateTime.Now - _jumpPressed) <= JumpEarlyTime) && + ((DateTime.Now - _lastOnFloor) <= JumpCoyoteTime)) { + _velocity.y = -JumpSpeed; + _jumpPressed = null; + _lastOnFloor = null; + } + } +} diff --git a/Viewport.cs b/Viewport.cs new file mode 100644 index 0000000..4b8667e --- /dev/null +++ b/Viewport.cs @@ -0,0 +1,55 @@ +using Godot; +using System; + +public class Viewport : Godot.Viewport +{ + public TextureRect ViewportTexture { get; private set; } + public Vector2 DefaultSize { get; private set; } + public int Scale { get; private set; } + + public override void _Ready() + { + ViewportTexture = GetNode("../ViewportTexture"); + ViewportTexture.Texture = GetTexture(); + GetTree().Root.Connect("size_changed", this, "OnWindowResized"); + + RenderDirectToScreen = false; + DefaultSize = Size; + + OnWindowResized(); + SpawnBlocks(); + } + + private void OnWindowResized() + { + var windowSize = GetTree().Root.Size; + Scale = Math.Max(1, Mathf.RoundToInt(Mathf.Min( + OS.WindowSize.x / DefaultSize.x, + OS.WindowSize.y / DefaultSize.y))); + Size = windowSize / Scale; + ViewportTexture.RectScale = Vector2.One * Scale; + } + + private void SpawnBlocks() + { + var blockScene = GD.Load("res://Block.tscn"); + void SpawnBlockAt(int x, int y) + { + var block = (Node2D)blockScene.Instance(); + block.Position = new Vector2(x, y); + AddChild(block); + } + + // Top and bottom. + for (var x = 16; x <= (int)DefaultSize.x - 16; x += 16) { + SpawnBlockAt(x, 20); + SpawnBlockAt(x, (int)DefaultSize.y - 20); + } + + // Left and right. + for (var y = 36; y <= (int)DefaultSize.y - 36; y += 16) { + SpawnBlockAt(16, y); + SpawnBlockAt((int)DefaultSize.x - 16, y); + } + } +} diff --git a/YourfortV.csproj b/YourfortV.csproj new file mode 100644 index 0000000..cb988d2 --- /dev/null +++ b/YourfortV.csproj @@ -0,0 +1,5 @@ + + + net472 + + \ No newline at end of file diff --git a/YourfortV.sln b/YourfortV.sln new file mode 100644 index 0000000..6a4f178 --- /dev/null +++ b/YourfortV.sln @@ -0,0 +1,19 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YourfortV", "YourfortV.csproj", "{FF89645B-804D-485D-BFAB-AA51330D8862}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + ExportDebug|Any CPU = ExportDebug|Any CPU + ExportRelease|Any CPU = ExportRelease|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FF89645B-804D-485D-BFAB-AA51330D8862}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FF89645B-804D-485D-BFAB-AA51330D8862}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FF89645B-804D-485D-BFAB-AA51330D8862}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU + {FF89645B-804D-485D-BFAB-AA51330D8862}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU + {FF89645B-804D-485D-BFAB-AA51330D8862}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU + {FF89645B-804D-485D-BFAB-AA51330D8862}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU + EndGlobalSection +EndGlobal diff --git a/default_env.tres b/default_env.tres new file mode 100644 index 0000000..20207a4 --- /dev/null +++ b/default_env.tres @@ -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 ) diff --git a/gfx/block.png b/gfx/block.png new file mode 100644 index 0000000..47b1029 Binary files /dev/null and b/gfx/block.png differ diff --git a/gfx/block.png.import b/gfx/block.png.import new file mode 100644 index 0000000..70bd5a8 --- /dev/null +++ b/gfx/block.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/block.png-60e5fe55f4421ac5893119a21190be18.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://gfx/block.png" +dest_files=[ "res://.import/block.png-60e5fe55f4421ac5893119a21190be18.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=false +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 +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/gfx/cursor.png b/gfx/cursor.png new file mode 100644 index 0000000..12b1922 Binary files /dev/null and b/gfx/cursor.png differ diff --git a/gfx/cursor.png.import b/gfx/cursor.png.import new file mode 100644 index 0000000..ce939d3 --- /dev/null +++ b/gfx/cursor.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/cursor.png-3b96f8448db3dedf6af5b6b7fc13768f.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://gfx/cursor.png" +dest_files=[ "res://.import/cursor.png-3b96f8448db3dedf6af5b6b7fc13768f.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 +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/gfx/icon.png b/gfx/icon.png new file mode 100644 index 0000000..c98fbb6 Binary files /dev/null and b/gfx/icon.png differ diff --git a/gfx/icon.png.import b/gfx/icon.png.import new file mode 100644 index 0000000..9e6ed24 --- /dev/null +++ b/gfx/icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/icon.png-3866f89624e56ede0f5895d50d47f7c1.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://gfx/icon.png" +dest_files=[ "res://.import/icon.png-3866f89624e56ede0f5895d50d47f7c1.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 +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/gfx/player.png b/gfx/player.png new file mode 100644 index 0000000..e5542cd Binary files /dev/null and b/gfx/player.png differ diff --git a/gfx/player.png.import b/gfx/player.png.import new file mode 100644 index 0000000..c48e6c3 --- /dev/null +++ b/gfx/player.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/player.png-3013952efb05378239c0b5ec08f70756.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://gfx/player.png" +dest_files=[ "res://.import/player.png-3013952efb05378239c0b5ec08f70756.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=false +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 +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/project.godot b/project.godot new file mode 100644 index 0000000..ee2ffa5 --- /dev/null +++ b/project.godot @@ -0,0 +1,85 @@ +; 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": "", +"class": "GitAPI", +"language": "NativeScript", +"path": "res://git_api.gdns" +} ] +_global_script_class_icons={ +"GitAPI": "" +} + +[application] + +config/name="YourfortV" +run/main_scene="res://GameScene.tscn" +config/icon="res://gfx/icon.png" + +[display] + +window/size/width=1280 +window/size/height=720 +window/stretch/aspect="expand" + +[gdnative] + +singletons=[ "res://git_api.gdnlib" ] + +[importer_defaults] + +texture={ +"compress/bptc_ldr": 0, +"compress/hdr_mode": 0, +"compress/lossy_quality": 0.7, +"compress/mode": 0, +"compress/normal_map": 0, +"detect_3d": false, +"flags/anisotropic": false, +"flags/filter": false, +"flags/mipmaps": false, +"flags/repeat": 0, +"flags/srgb": 2, +"process/HDR_as_SRGB": false, +"process/fix_alpha_border": true, +"process/invert_color": false, +"process/premult_alpha": false, +"size_limit": 0, +"stream": false, +"svg/scale": 1.0 +} + +[input] + +move_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":65,"unicode":0,"echo":false,"script":null) +, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":-1.0,"script":null) + ] +} +move_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":68,"unicode":0,"echo":false,"script":null) +, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":1.0,"script":null) + ] +} +move_jump={ +"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":32,"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":87,"unicode":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":1,"pressure":0.0,"pressed":false,"script":null) + ] +} + +[rendering] + +quality/2d/use_pixel_snap=true +environment/default_environment="res://default_env.tres"