Add new cool light beam for the flashlight
Co-authored-by: Евгений Титаренко <frundle@teasanctuary.ru>
34
invert.py
Normal file
|
@ -0,0 +1,34 @@
|
|||
# shout out to FriendlyWithMeat
|
||||
|
||||
from PIL import Image
|
||||
from pathlib import Path
|
||||
import os
|
||||
from PIL.ImageOps import invert
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
prog='invert.py',
|
||||
description='Took images from INPUT_FOLDER, invert them and save in OUTPUT_FOLDER.')
|
||||
parser.add_argument('INPUT_FOLDER')
|
||||
parser.add_argument('OUTPUT_FOLDER')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
WORK_DIR = Path(args.INPUT_FOLDER)
|
||||
IMG_EXTS = set((".png",))
|
||||
OUT_DIR = Path(args.OUTPUT_FOLDER)
|
||||
|
||||
|
||||
OUT_DIR.mkdir(exist_ok=True)
|
||||
dir_contents = os.listdir(WORK_DIR)
|
||||
for elem in dir_contents:
|
||||
img_file = Path(os.path.join(WORK_DIR, elem))
|
||||
if img_file.suffix in IMG_EXTS:
|
||||
image = Image.open(img_file)
|
||||
r, g, b, a = image.convert('RGBA').split()
|
||||
rgb_image = Image.merge('RGB', (r,g,b))
|
||||
inv_image = invert(rgb_image)
|
||||
r, g, b = inv_image.split()
|
||||
final_img = Image.merge('RGBA', (r,g,b,a))
|
||||
save_path = Path(os.path.join(OUT_DIR, elem))
|
||||
final_img.save(save_path)
|
|
@ -15,5 +15,4 @@ shape = SubResource("RectangleShape2D_5hhj3")
|
|||
|
||||
[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="."]
|
||||
sprite_frames = ExtResource("1_8jl58")
|
||||
animation = &"up"
|
||||
frame_progress = 0.975256
|
||||
animation = &"down"
|
||||
|
|
3
process_sprites.bat
Normal file
|
@ -0,0 +1,3 @@
|
|||
python invert.py sprites_orig sprites
|
||||
python invert.py sprites_orig\player sprites\player
|
||||
pause
|
|
@ -37,8 +37,13 @@ project/assembly_name="1bit-game-jam"
|
|||
textures/canvas_textures/default_texture_filter=0
|
||||
renderer/rendering_method="mobile"
|
||||
textures/lossless_compression/force_png=true
|
||||
textures/default_filters/use_nearest_mipmap_filter=true
|
||||
textures/default_filters/anisotropic_filtering_level=0
|
||||
environment/ssao/quality=0
|
||||
environment/ssil/quality=0
|
||||
anti_aliasing/screen_space_roughness_limiter/enabled=false
|
||||
textures/decals/filter=0
|
||||
textures/light_projectors/filter=0
|
||||
environment/glow/upscale_mode=0
|
||||
environment/defaults/default_clear_color=Color(0, 0, 0, 1)
|
||||
2d/snap/snap_2d_transforms_to_pixel=true
|
||||
|
|
1
requirements.txt
Normal file
|
@ -0,0 +1 @@
|
|||
Pillow>=10.0.0
|
|
@ -1,49 +1,92 @@
|
|||
[gd_scene load_steps=6 format=3 uid="uid://dhn7yt46fyac8"]
|
||||
[gd_scene load_steps=11 format=3 uid="uid://dhn7yt46fyac8"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://bhulqhxesd5gc" path="res://prefabs/player.tscn" id="1_65a7v"]
|
||||
[ext_resource type="Texture2D" uid="uid://py6qiu3rm7cu" path="res://sprites/brickwall.png" id="2_edqdh"]
|
||||
[ext_resource type="Texture2D" uid="uid://dlbl6d4yghvht" path="res://sprites/mask.png" id="3_8o315"]
|
||||
[ext_resource type="Script" path="res://scripts/Flashlight.cs" id="3_cylxo"]
|
||||
[ext_resource type="Material" uid="uid://xuvxq5hy1dt" path="res://shaders/light_shader_material.tres" id="4_ro05e"]
|
||||
[ext_resource type="Script" path="res://scripts/GameCamera.cs" id="6_quua3"]
|
||||
[ext_resource type="Script" path="res://scripts/PointLight2DWorkaround.cs" id="6_slohe"]
|
||||
|
||||
[sub_resource type="CanvasItemMaterial" id="CanvasItemMaterial_wg1ao"]
|
||||
light_mode = 2
|
||||
|
||||
[node name="Root" type="Node2D"]
|
||||
[sub_resource type="ViewportTexture" id="ViewportTexture_nnmvo"]
|
||||
viewport_path = NodePath("FlashlightViewport")
|
||||
|
||||
[node name="Player" parent="." node_paths=PackedStringArray("FlashlightUI", "FlashlightWorld") instance=ExtResource("1_65a7v")]
|
||||
position = Vector2(19, 4)
|
||||
FlashlightUI = NodePath("../CanvasLayer/FlashlightUI")
|
||||
FlashlightWorld = NodePath("../Camera2D/PointLight2D")
|
||||
[sub_resource type="CanvasItemMaterial" id="CanvasItemMaterial_au1d0"]
|
||||
light_mode = 2
|
||||
|
||||
[node name="Root" type="Node2D"]
|
||||
|
||||
[node name="TestWall" type="Sprite2D" parent="."]
|
||||
light_mask = 2
|
||||
material = SubResource("CanvasItemMaterial_wg1ao")
|
||||
position = Vector2(-108, -74)
|
||||
position = Vector2(58, 37)
|
||||
texture = ExtResource("2_edqdh")
|
||||
|
||||
[node name="CanvasLayer" type="CanvasLayer" parent="."]
|
||||
[node name="Player" parent="." instance=ExtResource("1_65a7v")]
|
||||
position = Vector2(19, 4)
|
||||
|
||||
[node name="FlashlightUI" type="Sprite2D" parent="CanvasLayer"]
|
||||
clip_children = 1
|
||||
[node name="FlashlightViewport" type="SubViewport" parent="."]
|
||||
transparent_bg = true
|
||||
snap_2d_transforms_to_pixel = true
|
||||
snap_2d_vertices_to_pixel = true
|
||||
canvas_item_default_texture_filter = 0
|
||||
size = Vector2i(256, 192)
|
||||
render_target_update_mode = 4
|
||||
|
||||
[node name="Circle" type="Sprite2D" parent="FlashlightViewport"]
|
||||
texture = ExtResource("3_8o315")
|
||||
|
||||
[node name="InvertRect" type="ColorRect" parent="CanvasLayer/FlashlightUI"]
|
||||
material = ExtResource("4_ro05e")
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -32.0
|
||||
offset_top = -32.0
|
||||
offset_right = -32.0
|
||||
offset_bottom = -32.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
metadata/_edit_use_anchors_ = true
|
||||
[node name="PlayerCircle" type="Sprite2D" parent="FlashlightViewport"]
|
||||
position = Vector2(13.61, 14.405)
|
||||
scale = Vector2(0.5, 0.5)
|
||||
texture = ExtResource("3_8o315")
|
||||
|
||||
[node name="Camera2D" type="Camera2D" parent="."]
|
||||
[node name="Triangle" type="Polygon2D" parent="FlashlightViewport"]
|
||||
polygon = PackedVector2Array(-21, -25, 31, 29, -42, 31)
|
||||
|
||||
[node name="PointLight2D" type="PointLight2D" parent="Camera2D"]
|
||||
[node name="Controller" type="Node" parent="FlashlightViewport" node_paths=PackedStringArray("Player", "Camera", "Circle", "PlayerCircle", "Polygon")]
|
||||
script = ExtResource("3_cylxo")
|
||||
Player = NodePath("../../Player")
|
||||
Camera = NodePath("../../PlayerCamera")
|
||||
Circle = NodePath("../Circle")
|
||||
PlayerCircle = NodePath("../PlayerCircle")
|
||||
Polygon = NodePath("../Triangle")
|
||||
|
||||
[node name="PlayerCamera" type="Camera2D" parent="."]
|
||||
script = ExtResource("6_quua3")
|
||||
|
||||
[node name="PointLight2D" type="PointLight2D" parent="PlayerCamera" node_paths=PackedStringArray("LightViewport")]
|
||||
energy = 16.0
|
||||
blend_mode = 2
|
||||
range_item_cull_mask = 2
|
||||
script = ExtResource("6_slohe")
|
||||
LightViewport = NodePath("../../FlashlightViewport")
|
||||
|
||||
[node name="CanvasLayer" type="CanvasLayer" parent="."]
|
||||
|
||||
[node name="FlashlightUI" type="TextureRect" parent="CanvasLayer"]
|
||||
clip_children = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = SubResource("ViewportTexture_nnmvo")
|
||||
|
||||
[node name="InvertRect" type="ColorRect" parent="CanvasLayer/FlashlightUI"]
|
||||
material = ExtResource("4_ro05e")
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||
light_mask = 2
|
||||
material = SubResource("CanvasItemMaterial_au1d0")
|
||||
position = Vector2(-83, 43)
|
||||
texture = ExtResource("3_8o315")
|
||||
|
|
9
scripts/Constants.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
using Godot;
|
||||
|
||||
public static class Constants
|
||||
{
|
||||
public static readonly Vector2 ScreenSize = new(256, 192);
|
||||
public static readonly Vector2 HalfScreenSize = ScreenSize / 2;
|
||||
|
||||
public const float MaxFlashlightRadius = 32;
|
||||
}
|
48
scripts/Flashlight.cs
Normal file
|
@ -0,0 +1,48 @@
|
|||
using Godot;
|
||||
|
||||
public partial class Flashlight : Node
|
||||
{
|
||||
[Export] public Player Player;
|
||||
[Export] public GameCamera Camera;
|
||||
|
||||
[Export] public Node2D Circle;
|
||||
[Export] public Node2D PlayerCircle;
|
||||
[Export] public Polygon2D Polygon;
|
||||
|
||||
private float FlashlightRadius = Constants.MaxFlashlightRadius;
|
||||
|
||||
public override void _Process(double delta)
|
||||
{
|
||||
var playerScreenCenterPosition = Player.Position - Camera.Position;
|
||||
var flashlightScreenCenterPosition = Camera.FlashlightPosition - Camera.Position;
|
||||
|
||||
var playerScreenPosition = playerScreenCenterPosition + Constants.HalfScreenSize;
|
||||
PlayerCircle.Position = playerScreenPosition;
|
||||
|
||||
var flashlightScreenPosition = flashlightScreenCenterPosition + Constants.HalfScreenSize;
|
||||
var flashlightScale = FlashlightRadius / Constants.MaxFlashlightRadius;
|
||||
Circle.Position = flashlightScreenPosition;
|
||||
Circle.Scale = new Vector2(flashlightScale, flashlightScale);
|
||||
|
||||
var d = Camera.FlashlightPosition.DistanceTo(Player.Position);
|
||||
if (d <= FlashlightRadius)
|
||||
Polygon.Visible = false;
|
||||
else
|
||||
{
|
||||
Polygon.Visible = true;
|
||||
|
||||
var a = Mathf.Sqrt(d * d - FlashlightRadius * FlashlightRadius);
|
||||
var xy2 = Camera.FlashlightPosition - Player.Position;
|
||||
var angle = xy2.Angle();
|
||||
|
||||
var arcsinRd = Mathf.Asin(FlashlightRadius / d);
|
||||
var dslkhjdsflkhjsdfhlkjdfsjlk = angle + arcsinRd;
|
||||
var xy3 = a * new Vector2(Mathf.Cos(dslkhjdsflkhjsdfhlkjdfsjlk), Mathf.Sin(dslkhjdsflkhjsdfhlkjdfsjlk));
|
||||
var dslkhjdsflkhjsdfhlkjdfsjlk2 = angle - arcsinRd;
|
||||
var xy4 = a * new Vector2(Mathf.Cos(dslkhjdsflkhjsdfhlkjdfsjlk2), Mathf.Sin(dslkhjdsflkhjsdfhlkjdfsjlk2));
|
||||
|
||||
Polygon.Polygon = new[]
|
||||
{ playerScreenPosition, playerScreenPosition + xy3, playerScreenPosition + xy4 };
|
||||
}
|
||||
}
|
||||
}
|
19
scripts/GameCamera.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
using Godot;
|
||||
|
||||
public partial class GameCamera : Camera2D
|
||||
{
|
||||
/// <summary>
|
||||
/// World position of the flashlight
|
||||
/// </summary>
|
||||
public Vector2 FlashlightPosition;
|
||||
|
||||
public override void _Input(InputEvent @event)
|
||||
{
|
||||
base._Input(@event);
|
||||
|
||||
if (@event is InputEventMouseMotion eventMouseMotion)
|
||||
{
|
||||
FlashlightPosition = eventMouseMotion.Position - Constants.HalfScreenSize + Position;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,52 +1,37 @@
|
|||
using Godot;
|
||||
using System;
|
||||
|
||||
public partial class Player : CharacterBody2D
|
||||
{
|
||||
[Export] public Node2D FlashlightUI;
|
||||
[Export] public Node2D FlashlightWorld;
|
||||
[Export] public const float Speed = 50.0f;
|
||||
|
||||
[Export] public const float Speed = 50.0f;
|
||||
protected AnimatedSprite2D Sprite;
|
||||
|
||||
protected AnimatedSprite2D Sprite;
|
||||
public override void _Ready()
|
||||
{
|
||||
base._Ready();
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
base._Ready();
|
||||
Sprite = (AnimatedSprite2D)FindChild("AnimatedSprite2D");
|
||||
}
|
||||
|
||||
Sprite = (AnimatedSprite2D)FindChild("AnimatedSprite2D");
|
||||
}
|
||||
public override void _PhysicsProcess(double delta)
|
||||
{
|
||||
Vector2 velocity = Velocity;
|
||||
|
||||
public override void _PhysicsProcess(double delta)
|
||||
{
|
||||
Vector2 velocity = Velocity;
|
||||
// Get the input direction and handle the movement/deceleration.
|
||||
// As good practice, you should replace UI actions with custom gameplay actions.
|
||||
Vector2 direction = Input.GetVector("ui_left", "ui_right", "ui_up", "ui_down");
|
||||
if (direction != Vector2.Zero)
|
||||
{
|
||||
velocity.X = direction.X * Speed;
|
||||
velocity.Y = direction.Y * Speed;
|
||||
}
|
||||
else
|
||||
{
|
||||
velocity.X = Mathf.MoveToward(Velocity.X, 0, Speed);
|
||||
velocity.Y = Mathf.MoveToward(Velocity.Y, 0, Speed);
|
||||
}
|
||||
|
||||
// Get the input direction and handle the movement/deceleration.
|
||||
// As good practice, you should replace UI actions with custom gameplay actions.
|
||||
Vector2 direction = Input.GetVector("ui_left", "ui_right", "ui_up", "ui_down");
|
||||
if (direction != Vector2.Zero)
|
||||
{
|
||||
velocity.X = direction.X * Speed;
|
||||
velocity.Y = direction.Y * Speed;
|
||||
}
|
||||
else
|
||||
{
|
||||
velocity.X = Mathf.MoveToward(Velocity.X, 0, Speed);
|
||||
velocity.Y = Mathf.MoveToward(Velocity.Y, 0, Speed);
|
||||
}
|
||||
|
||||
Velocity = velocity;
|
||||
MoveAndSlide();
|
||||
}
|
||||
|
||||
public override void _Input(InputEvent @event)
|
||||
{
|
||||
base._Input(@event);
|
||||
|
||||
if (@event is InputEventMouseMotion eventMouseMotion)
|
||||
{
|
||||
FlashlightUI.Position = eventMouseMotion.Position;
|
||||
FlashlightWorld.Position = eventMouseMotion.Position - new Vector2(128F, 96F);
|
||||
}
|
||||
}
|
||||
}
|
||||
Velocity = velocity;
|
||||
MoveAndSlide();
|
||||
}
|
||||
}
|
||||
|
|
16
scripts/PointLight2DWorkaround.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using Godot;
|
||||
using System;
|
||||
|
||||
[Tool]
|
||||
public partial class PointLight2DWorkaround : PointLight2D
|
||||
{
|
||||
[Export] public Viewport LightViewport;
|
||||
|
||||
public override void _Process(double delta)
|
||||
{
|
||||
base._Process(delta);
|
||||
|
||||
Texture = null;
|
||||
Texture = LightViewport.GetTexture();
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 248 B After Width: | Height: | Size: 245 B |
Before Width: | Height: | Size: 651 B After Width: | Height: | Size: 638 B |
Before Width: | Height: | Size: 662 B After Width: | Height: | Size: 635 B |
Before Width: | Height: | Size: 512 B After Width: | Height: | Size: 491 B |
0
sprites_orig/.gdignore
Normal file
BIN
sprites_orig/brickwall.png
Normal file
After Width: | Height: | Size: 245 B |
BIN
sprites_orig/player/mc-walk-bottom.png
Normal file
After Width: | Height: | Size: 651 B |
BIN
sprites_orig/player/mc-walk-side.png
Normal file
After Width: | Height: | Size: 662 B |
BIN
sprites_orig/player/mc-walk-up.png
Normal file
After Width: | Height: | Size: 512 B |