worker on implementing the scene system

This commit is contained in:
Linus Vogel 2025-12-09 23:07:27 +01:00
parent d933b16d3d
commit b7be82d7b1
26 changed files with 625 additions and 4 deletions

View File

@ -5,11 +5,13 @@ public partial class Controller : Window
{ {
private double _closeTime = 0; private double _closeTime = 0;
private bool _screenReady = true; private bool _screenReady = true;
private bool _loadReady = true;
private Button _btnScene1; private Button _btnScene1;
private Button _btnScene2; private Button _btnScene2;
private Button _btnScene3; private Button _btnScene3;
private Button _btnScene4; private Button _btnScene4;
private Button _btnLoad;
private Button _btnScreen; private Button _btnScreen;
private Button _btnClose; private Button _btnClose;
@ -22,6 +24,7 @@ public partial class Controller : Window
this._btnScene3 = this.GetNode<Button>("BtnScene3"); this._btnScene3 = this.GetNode<Button>("BtnScene3");
this._btnScene4 = this.GetNode<Button>("BtnScene4"); this._btnScene4 = this.GetNode<Button>("BtnScene4");
this._btnLoad = this.GetNode<Button>("BtnLoad");
this._btnScreen = this.GetNode<Button>("BtnScreen"); this._btnScreen = this.GetNode<Button>("BtnScreen");
this._btnClose = this.GetNode<Button>("BtnClose"); this._btnClose = this.GetNode<Button>("BtnClose");
@ -44,6 +47,8 @@ public partial class Controller : Window
this._btnScene3.Size = btnSize; this._btnScene3.Size = btnSize;
this._btnScene4.Size = btnSize; this._btnScene4.Size = btnSize;
this._btnLoad.Size = btnSize;
this._btnLoad.Position = border + (new Vector2(3, 2)*rasterSize);
this._btnScreen.Size = btnSize; this._btnScreen.Size = btnSize;
this._btnScreen.Position = border + (new Vector2(3, 3)*rasterSize); this._btnScreen.Position = border + (new Vector2(3, 3)*rasterSize);
@ -59,15 +64,32 @@ public partial class Controller : Window
this._btnClose.AddThemeColorOverride("font_pressed_color", new Color((float)this._closeTime, 0, 0)); this._btnClose.AddThemeColorOverride("font_pressed_color", new Color((float)this._closeTime, 0, 0));
if (this._closeTime > 1) this.GetTree().Quit(); if (this._closeTime > 1) this.GetTree().Quit();
// Get a reference to the root script
MainScript mainScript = (MainScript)this.GetTree().GetRoot().GetNode<MainScript>("Main");
if (this._btnScreen.IsPressed() && this._screenReady) if (this._btnScreen.IsPressed() && this._screenReady)
{ {
MainScript windowScript = (MainScript)this.GetTree().GetRoot().GetNode<MainScript>("Main"); mainScript.SetFullScreen();
windowScript.SetFullScreen();
this._screenReady = false; this._screenReady = false;
} }
else if (!this._btnScreen.IsPressed() && !this._screenReady) else if (!this._btnScreen.IsPressed() && !this._screenReady)
{ {
this._screenReady = true; this._screenReady = true;
} }
if (this._btnScene1.IsPressed()) mainScript.SetScene(1);
if (this._btnScene2.IsPressed()) mainScript.SetScene(2);
if (this._btnScene3.IsPressed()) mainScript.SetScene(3);
if (this._btnScene4.IsPressed()) mainScript.SetScene(4);
if (this._btnLoad.IsPressed() && this._loadReady)
{
mainScript.UpdateConfig();
this._loadReady = false;
} else if (!this._btnLoad.IsPressed() && !this._loadReady)
{
this._loadReady = true;
} }
}
} }

View File

@ -1,9 +1,20 @@
using Godot; using Godot;
using System; using System;
using System.Collections.Generic;
using System.IO;
using StarSkyPresenter;
using YamlDotNet.Serialization;
using FileAccess = System.IO.FileAccess;
public partial class MainScript : Node2D public partial class MainScript : Node2D
{ {
private int _scene = 1;
private bool _configIsLoaded = false;
private Dictionary<string, Star> _stars = new Dictionary<string, Star>();
private List<Dictionary<string, StarSceneData>> _scenes = new List<Dictionary<string, StarSceneData>>()
// Called when the node enters the scene tree for the first time. // Called when the node enters the scene tree for the first time.
public override void _Ready() public override void _Ready()
{ {
@ -24,4 +35,82 @@ public partial class MainScript : Node2D
DisplayServer.WindowSetMode(DisplayServer.WindowMode.ExclusiveFullscreen, window.GetWindowId()); DisplayServer.WindowSetMode(DisplayServer.WindowMode.ExclusiveFullscreen, window.GetWindowId());
} }
public int GetScene()
{
return this._scene;
}
public void SetScene(int scene)
{
this._scene = scene;
}
public void UpdateConfig()
{
// check if config is already loaded
if (this._configIsLoaded)
{
return;
}
// Open the config file
FileStream configFile = File.Open("config.yaml", FileMode.Open, FileAccess.Read);
FileStream scenesFile = File.Open("scenes.yaml", FileMode.Open, FileAccess.Read);
Window projection = this.GetNode<Window>("/root/Main/Projection");
// deserialize the values
IDeserializer deser = new DeserializerBuilder().Build();
Objects obj_conf = deser.Deserialize<Objects>(new StreamReader(configFile));
List<Dictionary<string, StarSceneData>> scene_conf = deser.Deserialize<List<Dictionary<string, StarSceneData>>>(new StreamReader(scenesFile));
Dictionary<string, Star> stars = new Dictionary<string, Star>();
foreach (StarConfig star_config in obj_conf.stars)
{
Sprite2D sprite = new Sprite2D();
Image image = Image.LoadFromFile("resources/" + star_config.image);
ImageTexture texture = ImageTexture.CreateFromImage(image);
sprite.SetTexture(texture);
sprite.Position = new Vector2(star_config.x, star_config.y);
Star star = new Star
{
Id = star_config.id,
X = star_config.x,
Y = star_config.y,
Rot = star_config.rot,
Scale = star_config.scale,
Sprite = sprite
};
stars.Add(star_config.id, star);
}
foreach (Node child in projection.GetChildren())
{
projection.RemoveChild(child);
child.QueueFree();
}
foreach (KeyValuePair<string, Star> star in stars)
{
projection.AddChild(star.Value.Sprite);
}
List<Dictionary<string, Star>> scenes = new List<Dictionary<string, Star>>();
foreach (var scene in scene_conf)
{
foreach (KeyValuePair<string, StarSceneData> kv in scene)
{
// TODO: continue here
}
}
configFile.Close();
scenesFile.Close();
this._configIsLoaded = true;
}
} }

14
Objects.cs Normal file
View File

@ -0,0 +1,14 @@
using System.Collections;
using System.Collections.Generic;
namespace StarSkyPresenter;
public class Objects
{
public List<StarConfig> stars { get; set; }
public string background { get; set; }
public float frameRate { get; set; }
}

1
Objects.cs.uid Normal file
View File

@ -0,0 +1 @@
uid://bn8e7pauk6fxh

View File

@ -1,16 +1,40 @@
using Godot; using Godot;
using System; using System;
using System.Collections.Generic;
using YamlDotNet.Serialization;
public partial class Projection : Window public partial class Projection : Window
{ {
private double _sceneTime = 0;
private int _lastScene = 1;
private int _activeScene = 1;
// Called when the node enters the scene tree for the first time. // Called when the node enters the scene tree for the first time.
public override void _Ready() public override void _Ready()
{ {
} }
// Called every frame. 'delta' is the elapsed time since the previous frame. // Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta) public override void _Process(double delta)
{ {
// get MainScript instance
MainScript mainScript = (MainScript)this.GetTree().GetRoot().GetNode<MainScript>("Main");
Window projectionWindow = GetNode<Window>("/root/Main/Projection");
// check for scene update and if so reset the scene time
if (mainScript.GetScene() != this._activeScene)
{
this._lastScene = this._activeScene;
this._activeScene = mainScript.GetScene();
this._sceneTime = 0;
}
else
{
this._sceneTime += delta;
}
} }
} }

35
Star.cs Normal file
View File

@ -0,0 +1,35 @@
using System.Diagnostics.CodeAnalysis;
using Godot;
namespace StarSkyPresenter;
[SuppressMessage("ReSharper", "InconsistentNaming")]
public class StarConfig
{
public string id { get; set; }
public float x { get; set; }
public float y { get; set; }
public float rot { get; set; }
public float scale { get; set; }
public string image { get; set; }
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public class StarSceneData
{
public float x { get; set; }
public float y { get; set; }
public float rot { get; set; }
public float scale { get; set; }
}
public class Star
{
public string Id { get; set; }
public float X { get; set; }
public float Y { get; set; }
public float Rot { get; set; }
public float Alpha { get; set; } = 0;
public float Scale { get; set; }
public Sprite2D Sprite { get; set; }
}

1
Star.cs.uid Normal file
View File

@ -0,0 +1 @@
uid://oeiqlm4tnbv7

View File

@ -6,5 +6,10 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Update="GodotSharp" Version="4.6.0-dev.6" /> <PackageReference Update="GodotSharp" Version="4.6.0-dev.6" />
<PackageReference Include="YamlDotNet" Version="16.3.0" />
</ItemGroup>
<ItemGroup>
<Content Include="config.yaml" />
<Content Include="scenes.yaml" />
</ItemGroup> </ItemGroup>
</Project> </Project>

18
config.yaml Normal file
View File

@ -0,0 +1,18 @@
stars:
- id: star-1
x: 50
y: 50
rot: 15
scale: 5
image: nice-star-1.png
- id: star-2
x: 25
y: 25
rot: 10
scale: 4
image: nice-star-2.png
background: background-01.jpg
frameRate: 30

View File

@ -1,6 +1,6 @@
[gd_scene load_steps=4 format=3 uid="uid://lychvawyirrs"] [gd_scene load_steps=4 format=3 uid="uid://lychvawyirrs"]
[ext_resource type="Script" uid="uid://77crqavwamsd" path="res://Main.cs" id="1_0e48y"] [ext_resource type="Script" uid="uid://77crqavwamsd" path="res://MainScript.cs" id="1_0e48y"]
[ext_resource type="Script" uid="uid://dg0qtnm4epowu" path="res://Controller.cs" id="1_wtcfe"] [ext_resource type="Script" uid="uid://dg0qtnm4epowu" path="res://Controller.cs" id="1_wtcfe"]
[ext_resource type="Script" uid="uid://criv4i3x63akl" path="res://Projection.cs" id="2_0e48y"] [ext_resource type="Script" uid="uid://criv4i3x63akl" path="res://Projection.cs" id="2_0e48y"]
@ -9,7 +9,7 @@ script = ExtResource("1_0e48y")
[node name="Controller" type="Window" parent="."] [node name="Controller" type="Window" parent="."]
oversampling_override = 1.0 oversampling_override = 1.0
position = Vector2i(-650, 0) position = Vector2i(0, 36)
size = Vector2i(640, 480) size = Vector2i(640, 480)
script = ExtResource("1_wtcfe") script = ExtResource("1_wtcfe")
@ -53,7 +53,13 @@ offset_right = 8.0
offset_bottom = 8.0 offset_bottom = 8.0
text = "Screen" text = "Screen"
[node name="BtnLoad" type="Button" parent="Controller"]
offset_right = 8.0
offset_bottom = 8.0
text = "Load Config"
[node name="Projection" type="Window" parent="."] [node name="Projection" type="Window" parent="."]
oversampling_override = 1.0 oversampling_override = 1.0
position = Vector2i(0, 36)
size = Vector2i(1920, 1080) size = Vector2i(1920, 1080)
script = ExtResource("2_0e48y") script = ExtResource("2_0e48y")

BIN
resources/BasicStar1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dcwh3yufsnjkx"
path="res://.godot/imported/BasicStar1.png-6ae1be3c0c394e31b0cc22e509e2b8d3.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://resources/BasicStar1.png"
dest_files=["res://.godot/imported/BasicStar1.png-6ae1be3c0c394e31b0cc22e509e2b8d3.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

BIN
resources/background-01.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 KiB

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://d3ddfgy71liqp"
path="res://.godot/imported/background-01.jpg-83659160a834cd7229c4f0caf4e7ad3e.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://resources/background-01.jpg"
dest_files=["res://.godot/imported/background-01.jpg-83659160a834cd7229c4f0caf4e7ad3e.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

116
resources/main_window.qml Normal file
View File

@ -0,0 +1,116 @@
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
ApplicationWindow {
id: mainWindow
visible: true
width: 800
height: 600
title: "StarSky Presenter"
flags: Qt.WindowCloseButtonHint | Qt.WindowStaysOnBottomHint
modality: Qt.ApplicationModal
Button {
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width * 0.9
y: parent.height * 0.85
height: parent.height * 0.1
text: "Close"
onClicked: controller_backend.close_application()
}
Text {
x: parent.width * 0.1 / 9 / 2
y: parent.height * 0.1 / 5 / 2
width: parent.width * 0.9
height: parent.height * 0.1
text: "Scene 1"
font.pixelSize: 60
color: "white"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
Button {
x: (parent.width * 0.1 / 9) * (0 + 0.5) + (parent.width * 0.9 / 9) * 0
y: (parent.height * 0.1 / 5) * (0 + 0.5) + (parent.height * 0.9 / 5) * 1
width: parent.width * 0.1
height: parent.height * 0.1
text: "Scene 1"
onClicked: controller_backend.select_scene(0)
}
Button {
x: (parent.width * 0.1 / 9) * (1 + 0.5) + (parent.width * 0.9 / 9) * 1
y: (parent.height * 0.1 / 5) * (0 + 0.5) + (parent.height * 0.9 / 5) * 1
width: parent.width * 0.1
height: parent.height * 0.1
text: "Scene 2"
onClicked: controller_backend.select_scene(1)
}
Button {
x: (parent.width * 0.1 / 9) * (2 + 0.5) + (parent.width * 0.9 / 9) * 2
y: (parent.height * 0.1 / 5) * (0 + 0.5) + (parent.height * 0.9 / 5) * 1
width: parent.width * 0.1
height: parent.height * 0.1
text: "Scene 3"
onClicked: controller_backend.select_scene(2)
}
Button {
x: (parent.width * 0.1 / 9) * (3 + 0.5) + (parent.width * 0.9 / 9) * 3
y: (parent.height * 0.1 / 5) * (0 + 0.5) + (parent.height * 0.9 / 5) * 1
width: parent.width * 0.1
height: parent.height * 0.1
text: "Scene 4"
onClicked: controller_backend.select_scene(3)
}
Button {
x: (parent.width * 0.1 / 9) * (4 + 0.5) + (parent.width * 0.9 / 9) * 4
y: (parent.height * 0.1 / 5) * (0 + 0.5) + (parent.height * 0.9 / 5) * 1
width: parent.width * 0.1
height: parent.height * 0.1
text: "Scene 5"
onClicked: controller_backend.select_scene(4)
}
Button {
x: (parent.width * 0.1 / 9) * (5 + 0.5) + (parent.width * 0.9 / 9) * 5
y: (parent.height * 0.1 / 5) * (0 + 0.5) + (parent.height * 0.9 / 5) * 1
width: parent.width * 0.1
height: parent.height * 0.1
text: "Scene 6"
onClicked: controller_backend.select_scene(5)
}
Button {
x: (parent.width * 0.1 / 9) * (6 + 0.5) + (parent.width * 0.9 / 9) * 6
y: (parent.height * 0.1 / 5) * (0 + 0.5) + (parent.height * 0.9 / 5) * 1
width: parent.width * 0.1
height: parent.height * 0.1
text: "Scene 7"
onClicked: controller_backend.select_scene(6)
}
Button {
x: (parent.width * 0.1 / 9) * (7 + 0.5) + (parent.width * 0.9 / 9) * 7
y: (parent.height * 0.1 / 5) * (0 + 0.5) + (parent.height * 0.9 / 5) * 1
width: parent.width * 0.1
height: parent.height * 0.1
text: "Scene 8"
onClicked: controller_backend.select_scene(7)
}
Button {
x: (parent.width * 0.1 / 9) * (8 + 0.5) + (parent.width * 0.9 / 9) * 8
y: (parent.height * 0.1 / 5) * (0 + 0.5) + (parent.height * 0.9 / 5) * 1
width: parent.width * 0.1
height: parent.height * 0.1
text: "Scene 9"
onClicked: controller_backend.select_scene(8)
}
}

BIN
resources/nice-star-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dmcdc016vsc4q"
path="res://.godot/imported/nice-star-1.png-5bfad1ee8c15d5f45a0d8444fd06ccd1.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://resources/nice-star-1.png"
dest_files=["res://.godot/imported/nice-star-1.png-5bfad1ee8c15d5f45a0d8444fd06ccd1.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

BIN
resources/nice-star-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c74kffg7ajty3"
path="res://.godot/imported/nice-star-2.png-0ee9c3966cebad5298d713eccc656361.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://resources/nice-star-2.png"
dest_files=["res://.godot/imported/nice-star-2.png-0ee9c3966cebad5298d713eccc656361.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

11
resources/objects.yml Normal file
View File

@ -0,0 +1,11 @@
stars:
- sid: star-1
x: 0.1
y: 0.1
scale: 5
alpha: 0
rot: 5
offset: 0
image: nice-star-1.png
background: background-01.jpg
framerate: 30

27
resources/scenes.yml Normal file
View File

@ -0,0 +1,27 @@
- star-1:
x: 1.1
y: 1.1
transition:
t: 5
fade_in: true
fade_out: false
x: sin
y: cos
- star-1:
x: 0.5
y: 0.5
transition:
t: 5
fade_in: false
fade_out: true
x: cos
y: sin
- star-1:
x: -0.1
y: 1.1
transition:
t: 5
fade_in: true
fade_out: false
x: sin
y: cos

BIN
resources/star0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dbmnaklv5xmm"
path="res://.godot/imported/star0.png-a508f887ffd74f565c8e3ed529ede633.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://resources/star0.png"
dest_files=["res://.godot/imported/star0.png-a508f887ffd74f565c8e3ed529ede633.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

BIN
resources/test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

40
resources/test.png.import Normal file
View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://du28x4hxdnv55"
path="res://.godot/imported/test.png-4aee7dd97c6bed0fc01f1e34f9c3f7fc.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://resources/test.png"
dest_files=["res://.godot/imported/test.png-4aee7dd97c6bed0fc01f1e34f9c3f7fc.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

12
scenes.yaml Normal file
View File

@ -0,0 +1,12 @@
- star-1:
x: 50
y: 50
star-2:
x: 60
y: 0
- star-1:
x: 10
y: 10
star-2:
x: 25
y: 25