Add initial resource and presenter classes for game entities and effects

This commit is contained in:
2025-10-13 12:11:50 +02:00
commit ad3e631d8c
75 changed files with 1423 additions and 0 deletions

4
.editorconfig Normal file
View File

@@ -0,0 +1,4 @@
root = true
[*]
charset = utf-8

2
.gitattributes vendored Normal file
View File

@@ -0,0 +1,2 @@
# Normalize EOL for all files that Git considers text files.
* text=auto eol=lf

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
# Godot 4+ specific ignores
.godot/
/android/

View File

@@ -0,0 +1,25 @@
using System.Collections.Generic;
using GameCore.ECS;
using Godot;
namespace CryptonymThunder.Code.Autoloads;
public partial class PresenterRegistry : Node
{
private readonly Dictionary<ulong, Entity> _instanceIdToEntity = new();
public void RegisterPresenter(Node presenterNode, Entity entity)
{
_instanceIdToEntity[presenterNode.GetInstanceId()] = entity;
}
public void UnregisterPresenter(Node presenterNode)
{
_instanceIdToEntity.Remove(presenterNode.GetInstanceId());
}
public bool TryGetEntity(ulong instanceId, out Entity entity)
{
return _instanceIdToEntity.TryGetValue(instanceId, out entity);
}
}

View File

@@ -0,0 +1 @@
uid://5twln2ckxjj8

View File

@@ -0,0 +1,17 @@
using GameCoreMath = GameCore.Math.Vector3;
using GodotMath = Godot.Vector3;
namespace CryptonymThunder.Code.Extensions;
public static class Vector3Extensions
{
public static GodotMath ToGodot(this GameCoreMath v)
{
return new GodotMath(v.X, v.Y, v.Z);
}
public static GameCoreMath ToGameCore(this GodotMath v)
{
return new GameCoreMath(v.X, v.Y, v.Z);
}
}

View File

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

View File

@@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using System.Linq;
using CryptonymThunder.Code.Resources;
using GameCore.Attributes;
using GameCore.Combat;
using GameCore.ECS.Interfaces;
using GameCore.Input;
using GameCore.Movement;
using GameCore.Physics;
using GameCore.Player;
using Godot;
namespace CryptonymThunder.Code.Factories;
public class ComponentFactory
{
private readonly Dictionary<Type, Func<Resource, IComponent>> _factories = new();
private readonly EffectFactory _effectFactory = new();
public ComponentFactory()
{
Register<AttributeComponentResource>(CreateAttributeComponent);
Register<WeaponComponentResource>(CreateWeaponComponent);
Register<ProjectileComponentResource>(CreateProjectileComponent);
Register<PositionComponentResource>(_ => new PositionComponent());
Register<VelocityComponentResource>(_ => new VelocityComponent());
Register<InputStateComponentResource>(_ => new InputStateComponent());
Register<PlayerComponentResource>(_ => new PlayerComponent());
Register<RotationComponentResource>(_ => new RotationComponent());
Register<CharacterStateComponentResource>(_ => new CharacterStateComponent());
}
public IComponent Create(Resource resource)
{
return _factories.TryGetValue(resource.GetType(), out var factory)
? factory(resource)
: null;
}
private void Register<TResource>(Func<TResource, IComponent> factory) where TResource : Resource
{
_factories[typeof(TResource)] = res => factory((TResource)res);
}
private static AttributeComponent CreateAttributeComponent(AttributeComponentResource resource)
{
var component = new AttributeComponent();
foreach (var (attribute, value) in resource.BaseValues)
{
component.SetBaseValue(attribute, value);
}
return component;
}
private WeaponComponent CreateWeaponComponent(WeaponComponentResource resource)
{
if (resource.WeaponData == null) return null;
var weaponData = resource.WeaponData;
var onFireEffects = weaponData.OnFireEffects.Select(_effectFactory.Create).ToList();
var onHitEffects = weaponData.OnHitEffects.Select(_effectFactory.Create).ToList();
return new WeaponComponent
{
FireRate = resource.WeaponData.FireRate,
OnFireEffects = onFireEffects,
OnHitEffects = onHitEffects,
};
}
private ProjectileComponent CreateProjectileComponent(ProjectileComponentResource resource)
{
return new ProjectileComponent
{
Lifetime = resource.Lifetime,
};
}
}

View File

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

View File

@@ -0,0 +1,24 @@
using System;
using System.Runtime.InteropServices.ComTypes;
using CryptonymThunder.Code.Resources;
using CryptonymThunder.Code.Resources.Effects;
using GameCore.Combat.Effects;
using GameCore.Combat.Interfaces;
namespace CryptonymThunder.Code.Factories;
public class EffectFactory
{
public IEffect Create(EffectResource resource)
{
return resource switch
{
FireProjectileEffectResource fire =>
new BulkProjectileEffect(fire.ProjectileArchetypeId, fire.Count, fire.SpreadAngle, fire.ProjectileSpeed),
DamageEffectResource damage => new DamageEffect(damage.Amount),
HitscanEffectResource hitscan => new HitscanEffect(hitscan.Range),
_ => throw new ArgumentOutOfRangeException(nameof(resource),
$"Effect type {resource.GetType().Name} not recognized")
};
}
}

View File

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

View File

@@ -0,0 +1,99 @@
using System.Collections.Generic;
using CryptonymThunder.Code.Autoloads;
using CryptonymThunder.Code.Resources;
using GameCore.ECS;
using GameCore.ECS.Interfaces;
using GameCore.Movement;
using GameCore.Physics;
using Godot;
using Godot.Collections;
namespace CryptonymThunder.Code.Factories;
public class PresenterFactory(
World world,
ComponentFactory componentFactory,
PresenterRegistry presenterRegistry,
Node sceneRoot)
{
private readonly World _world = world;
private readonly ComponentFactory _componentFactory = componentFactory;
private PresenterRegistry _presenterRegistry = presenterRegistry;
private readonly Node _sceneRoot = sceneRoot;
public PresenterData CreateEntityFromArchetype(EntityArchetype archetype, GameCore.Math.Vector3? position = null,
GameCore.Math.Vector3? rotation = null, GameCore.Math.Vector3? initialVelocity = null)
{
var entity = _world.CreateEntity();
foreach (var resource in archetype.ComponentResources)
{
var component = _componentFactory.Create(resource);
if (component != null) _world.AddComponent(entity, component);
}
var presenterNode = archetype.Scene.Instantiate<Node>();
if (presenterNode is not IEntityPresenter presenter)
{
GD.PrintErr($"Archetype scene '{archetype.ResourcePath}' root does not implement IEntityPresenter!");
presenterNode.QueueFree();
return default;
}
presenter.CoreEntity = entity;
var components = InitializePresenterComponents(presenterNode, entity);
if (position.HasValue && _world.GetComponent<PositionComponent>(entity) is { } posComp)
posComp.Position = position.Value;
if (rotation.HasValue && _world.GetComponent<RotationComponent>(entity) is { } rotComp)
rotComp.Rotation = rotation.Value;
if (initialVelocity.HasValue && _world.GetComponent<VelocityComponent>(entity) is { } velComp)
velComp.DesiredVelocity = initialVelocity.Value;
_sceneRoot.AddChild(presenterNode);
return new PresenterData(entity, presenter, components);
}
public PresenterData RegisterSceneEntity(Node presenterNode, Array<Resource> componentResources)
{
var entity = _world.CreateEntity();
foreach (var resource in componentResources)
{
var component = _componentFactory.Create(resource);
if (component != null) _world.AddComponent(entity, component);
}
if (presenterNode is not IEntityPresenter presenter)
{
GD.PrintErr($"Scene node '{presenterNode.Name}' does not implement IEntityPresenter!");
return default;
}
presenter.CoreEntity = entity;
var components = InitializePresenterComponents(presenterNode, entity);
return new PresenterData(entity, presenter, components);
}
private List<IPresenterComponent> InitializePresenterComponents(Node presenterNode, Entity entity)
{
_presenterRegistry.RegisterPresenter(presenterNode, entity);
var components = new List<IPresenterComponent>();
foreach (var child in presenterNode.GetChildren(true))
{
if (child is IPresenterComponent pComponent)
{
pComponent.Initialize(entity, _world);
components.Add(pComponent);
}
}
if (presenterNode is IPresenterComponent rootComponent)
{
rootComponent.Initialize(entity, _world);
components.Add(rootComponent);
}
return components;
}
}

View File

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

View File

@@ -0,0 +1,58 @@
using CryptonymThunder.Code.Extensions;
using GameCore.ECS;
using GameCore.ECS.Interfaces;
using GameCore.Input;
using GameCore.Movement;
using Godot;
namespace CryptonymThunder.Code.Presenters;
[GlobalClass]
public partial class CameraPresenterComponent : Node3D, IPresenterComponent
{
private Entity _coreEntity;
private World _world;
private Camera3D _camera;
private RotationComponent _rotationComponent;
private bool _cursorLocked = true;
public void Initialize(Entity coreEntity, World world)
{
_coreEntity = coreEntity;
_world = world;
_rotationComponent = _world.GetComponent<RotationComponent>(_coreEntity);
_camera = GetNode<Camera3D>("Camera3D");
if (_cursorLocked) Input.MouseMode = Input.MouseModeEnum.Captured;
}
public void SyncToPresentation(float delta)
{
if (_rotationComponent == null || _camera == null) return;
var coreRotation = _rotationComponent.Rotation;
_camera.Rotation = new Vector3(coreRotation.X, 0f, 0f);
}
public void SyncToCore(float delta)
{
}
public override void _Input(InputEvent @event)
{
if (Input.IsActionJustPressed("ui_cancel"))
{
if (_cursorLocked)
{
Input.MouseMode = Input.MouseModeEnum.Visible;
_cursorLocked = false;
}
else
{
Input.MouseMode = Input.MouseModeEnum.Captured;
_cursorLocked = true;
}
}
}
}

View File

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

View File

@@ -0,0 +1,66 @@
using CryptonymThunder.Code.Extensions;
using GameCore.ECS;
using GameCore.ECS.Interfaces;
using GameCore.Input;
using GameCore.Movement;
using GameCore.Physics;
using Godot;
namespace CryptonymThunder.Code.Presenters;
[GlobalClass]
public partial class CharacterBody3DPresenter : CharacterBody3D, IEntityPresenter, IPresenterComponent
{
private World _world;
private VelocityComponent _velocity;
private PositionComponent _position;
private RotationComponent _rotation;
private CharacterStateComponent _characterState;
private InputStateComponent _inputState;
private Camera3D _camera;
public Entity CoreEntity { get; set; }
public void Initialize(Entity coreEntity, World world)
{
CoreEntity = coreEntity;
_world = world;
_velocity = _world.GetComponent<VelocityComponent>(CoreEntity);
_position = _world.GetComponent<PositionComponent>(CoreEntity);
_rotation = _world.GetComponent<RotationComponent>(CoreEntity);
_inputState = _world.GetComponent<InputStateComponent>(CoreEntity);
_characterState = _world.GetComponent<CharacterStateComponent>(CoreEntity);
_camera = GetNode<Camera3D>("CameraPivot/Camera3D");
}
public void SyncToPresentation(float delta)
{
if (_rotation != null)
{
var coreRotation = _rotation.Rotation;
Rotation = new Vector3(Rotation.X, coreRotation.Y, Rotation.Z);
}
if (_velocity == null) return;
var godotVelocity = Velocity;
godotVelocity.X = _velocity.DesiredVelocity.X;
godotVelocity.Y = _velocity.DesiredVelocity.Y;
godotVelocity.Z = _velocity.DesiredVelocity.Z;
Velocity = godotVelocity;
MoveAndSlide();
}
public void SyncToCore(float delta)
{
if (_position != null) _position.Position = GlobalPosition.ToGameCore();
if (_velocity != null) _velocity.ActualVelocity = Velocity.ToGameCore();
if (_characterState != null) _characterState.IsOnFloor = IsOnFloor();
if (_inputState != null && _camera != null)
{
_inputState.MuzzlePosition = _camera.GlobalPosition.ToGameCore();
_inputState.MuzzleDirection = (-_camera.GlobalTransform.Basis.Z).ToGameCore();
}
}
}

View File

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

View File

@@ -0,0 +1,11 @@
using GameCore.ECS;
using GameCore.ECS.Interfaces;
using Godot;
namespace CryptonymThunder.Code.Presenters;
[GlobalClass]
public partial class EntityPresenter : Node3D, IEntityPresenter
{
public Entity CoreEntity { get; set; }
}

View File

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

View File

@@ -0,0 +1,157 @@
using System.Collections.Generic;
using CryptonymThunder.Code.Autoloads;
using CryptonymThunder.Code.Factories;
using CryptonymThunder.Code.Resources;
using CryptonymThunder.Code.Services;
using GameCore.Attributes;
using GameCore.Combat;
using GameCore.Config;
using GameCore.ECS;
using GameCore.ECS.Interfaces;
using GameCore.Events;
using GameCore.Input;
using GameCore.Movement;
using Godot;
namespace CryptonymThunder.Code.Presenters;
[GlobalClass]
public partial class GamePresenter : Node
{
[Export] private ArchetypeDatabase ArchetypesDatabase { get; set; }
[Export] private EntityArchetype PlayerArchetype { get; set; }
[Export] private SimulationConfigResource SimulationConfig { get; set; }
private World _world;
private PresenterRegistry _presenterRegistry;
private GodotInputService _inputService;
private GodotWorldQuery _worldQuery;
private PresenterFactory _presenterFactory;
private readonly Dictionary<int, List<IPresenterComponent>> _presenterComponents = new();
private readonly Dictionary<int, IEntityPresenter> _presenters = new();
public override void _Ready()
{
_presenterRegistry = GetNode<PresenterRegistry>("/root/PresenterRegistry");
_inputService = new GodotInputService();
_worldQuery = new GodotWorldQuery(this);
var simConfig = new SimulationConfig();
if (SimulationConfig != null)
{
simConfig.GravityStrength = SimulationConfig.GravityStrength;
}
_world = new World(_inputService, _worldQuery, simConfig);
_presenterFactory = new PresenterFactory(_world, new ComponentFactory(), _presenterRegistry, this);
_world.RegisterSystem(new PlayerInputSystem());
_world.RegisterSystem(new RotationSystem());
_world.RegisterSystem(new GroundMovementSystem());
_world.RegisterSystem(new GravitySystem());
_world.RegisterSystem(new JumpSystem());
_world.RegisterSystem(new AttributeSystem());
_world.RegisterSystem(new WeaponSystem());
_world.RegisterSystem(new ProjectileSystem());
_world.RegisterSystem(new ProjectileInitializationSystem(_world));
_world.RegisterSystem(new DamageSystem(_world));
_world.RegisterSystem(new ProjectileCleanupSystem());
_world.RegisterSystem(new DestructionSystem());
_world.Subscribe<EntityDiedEvent>(OnEntityDied);
_world.Subscribe<SpawnEntityEvent>(OnSpawnEntity);
RegisterAllSceneEntities();
var playerData = _presenterFactory.CreateEntityFromArchetype(PlayerArchetype);
_presenters.Add(playerData.Entity.Id, playerData.Presenter);
_presenterComponents.Add(playerData.Entity.Id, playerData.Components);
}
public override void _Input(InputEvent @event)
{
_inputService?.HandleInputEvent(@event);
}
public override void _PhysicsProcess(double delta)
{
if (_presenters.Count == 0) return;
_inputService.Update();
_world.Update((float)delta);
_world.ProcessEvents();
foreach (var componentList in _presenterComponents.Values)
{
foreach (var component in componentList)
{
component.SyncToPresentation((float)delta);
}
}
foreach (var componentList in _presenterComponents.Values)
{
foreach (var component in componentList)
{
component.SyncToCore((float)delta);
}
}
_inputService.LateUpdate();
}
private void OnSpawnEntity(SpawnEntityEvent @event)
{
if (ArchetypesDatabase.Archetypes.TryGetValue(@event.ArchetypeId, out var archetype))
{
var presenterData = _presenterFactory.CreateEntityFromArchetype(archetype, @event.Position, @event.Rotation, @event.InitialVelocity);
_presenters.Add(presenterData.Entity.Id, presenterData.Presenter);
_presenterComponents.Add(presenterData.Entity.Id, presenterData.Components);
_world.PublishEvent(new EntitySpawnedEvent(presenterData.Entity, @event.Owner, @event.ArchetypeId));
}
}
private void OnEntityDied(EntityDiedEvent e)
{
if (_presenters.Remove(e.Entity.Id, out var presenter))
{
_presenterRegistry.UnregisterPresenter(presenter as Node);
_presenterComponents.Remove(e.Entity.Id);
(presenter as Node)?.QueueFree();
}
}
private void RegisterAllSceneEntities()
{
var sceneEntities = GetTree().GetNodesInGroup("SceneEntities");
foreach (var node in sceneEntities)
{
if (node is SceneEntity sceneEntity)
{
var parentNode = sceneEntity.GetParent();
if (parentNode != null)
{
var presenterData = _presenterFactory.RegisterSceneEntity(parentNode, sceneEntity.ComponentResources);
_presenters.Add(presenterData.Entity.Id, presenterData.Presenter);
_presenterComponents.Add(presenterData.Entity.Id, presenterData.Components);
}
}
}
}
public Node GetPresenterNode(Entity entity)
{
if (_presenters.TryGetValue(entity.Id, out var presenter))
{
return presenter as Node;
}
return null;
}
}

View File

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

View File

@@ -0,0 +1,10 @@
using Godot;
using Godot.Collections;
namespace CryptonymThunder.Code.Presenters;
[GlobalClass]
public partial class SceneEntity : Node
{
[Export] public Array<Resource> ComponentResources { get; set; } = [];
}

View File

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

View File

@@ -0,0 +1,31 @@
using CryptonymThunder.Code.Extensions;
using GameCore.ECS;
using GameCore.ECS.Interfaces;
using GameCore.Physics;
using Godot;
namespace CryptonymThunder.Code.Presenters;
[GlobalClass]
public partial class TransformPresenterComponent : Node3D, IPresenterComponent, IEntityPresenter
{
private PositionComponent _position;
public Entity CoreEntity { get; set; }
public void Initialize(Entity coreEntity, World world)
{
CoreEntity = coreEntity;
_position = world.GetComponent<PositionComponent>(coreEntity);
}
public void SyncToPresentation(float delta)
{
if (_position != null) GlobalPosition = _position.Position.ToGodot();
}
public void SyncToCore(float delta)
{
}
}

View File

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

View File

@@ -0,0 +1,10 @@
using Godot;
using Godot.Collections;
namespace CryptonymThunder.Code.Resources;
[GlobalClass]
public partial class ArchetypeDatabase : Resource
{
[Export] public Dictionary<string, EntityArchetype> Archetypes { get; set; } = new();
}

View File

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

View File

@@ -0,0 +1,10 @@
using Godot;
using Attribute = GameCore.Attributes.Attribute;
namespace CryptonymThunder.Code.Resources;
[GlobalClass]
public partial class AttributeComponentResource : Resource
{
[Export] public Godot.Collections.Dictionary<Attribute, float> BaseValues { get; set; } = new();
}

View File

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

View File

@@ -0,0 +1,9 @@
using Godot;
namespace CryptonymThunder.Code.Resources;
[GlobalClass]
public partial class CharacterStateComponentResource : Resource
{
}

View File

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

View File

@@ -0,0 +1,9 @@
using Godot;
namespace CryptonymThunder.Code.Resources;
[GlobalClass]
public partial class EffectResource : Resource
{
}

View File

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

View File

@@ -0,0 +1,9 @@
using Godot;
namespace CryptonymThunder.Code.Resources.Effects;
[GlobalClass]
public partial class DamageEffectResource : EffectResource
{
[Export] public float Amount { get; set; } = 10f;
}

View File

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

View File

@@ -0,0 +1,12 @@
using Godot;
namespace CryptonymThunder.Code.Resources.Effects;
[GlobalClass]
public partial class FireProjectileEffectResource : EffectResource
{
[Export] public string ProjectileArchetypeId { get; set; }
[Export(PropertyHint.Range, "1,50,1")] public int Count { get; set; } = 1;
[Export(PropertyHint.Range, "0,90,0.1")] public float SpreadAngle { get; set; } = 0f;
[Export] public float ProjectileSpeed { get; set; } = 30f;
}

View File

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

View File

@@ -0,0 +1,9 @@
using Godot;
namespace CryptonymThunder.Code.Resources.Effects;
[GlobalClass]
public partial class HitscanEffectResource : EffectResource
{
[Export] public float Range { get; set; } = 100f;
}

View File

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

View File

@@ -0,0 +1,11 @@
using Godot;
using Godot.Collections;
namespace CryptonymThunder.Code.Resources;
[GlobalClass]
public partial class EntityArchetype : Resource
{
[Export] public PackedScene Scene { get; set; }
[Export] public Array<Resource> ComponentResources { get; set; } = [];
}

View File

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

View File

@@ -0,0 +1,9 @@
using Godot;
namespace CryptonymThunder.Code.Resources;
[GlobalClass]
public partial class InputStateComponentResource : Resource
{
}

View File

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

View File

@@ -0,0 +1,9 @@
using Godot;
namespace CryptonymThunder.Code.Resources;
[GlobalClass]
public partial class PlayerComponentResource : Resource
{
}

View File

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

View File

@@ -0,0 +1,9 @@
using Godot;
namespace CryptonymThunder.Code.Resources;
[GlobalClass]
public partial class PositionComponentResource : Resource
{
}

View File

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

View File

@@ -0,0 +1,10 @@
using Godot;
namespace CryptonymThunder.Code.Resources;
[GlobalClass]
public partial class ProjectileComponentResource : Resource
{
[Export] public float Speed { get; set; } = 50.0f;
[Export] public float Lifetime { get; set; } = 5.0f;
}

View File

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

View File

@@ -0,0 +1,9 @@
using Godot;
namespace CryptonymThunder.Code.Resources;
[GlobalClass]
public partial class RotationComponentResource : Resource
{
}

View File

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

View File

@@ -0,0 +1,9 @@
using Godot;
namespace CryptonymThunder.Code.Resources;
[GlobalClass]
public partial class SimulationConfigResource : Resource
{
[Export] public float GravityStrength { get; set; } = 9.81f;
}

View File

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

View File

@@ -0,0 +1,9 @@
using Godot;
namespace CryptonymThunder.Code.Resources;
[GlobalClass]
public partial class VelocityComponentResource : Resource
{
}

View File

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

View File

@@ -0,0 +1,9 @@
using Godot;
namespace CryptonymThunder.Code.Resources;
[GlobalClass]
public partial class WeaponComponentResource : Resource
{
[Export] public WeaponResource WeaponData { get; set; }
}

View File

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

View File

@@ -0,0 +1,14 @@
using GameCore.Combat;
using Godot;
namespace CryptonymThunder.Code.Resources;
[GlobalClass]
public partial class WeaponResource : Resource
{
[Export] public float FireRate { get; set; } = 1.0f;
[ExportGroup("Effects")]
[Export] public Godot.Collections.Array<EffectResource> OnFireEffects { get; set; } = [];
[Export] public Godot.Collections.Array<EffectResource> OnHitEffects { get; set; } = [];
}

View File

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

View File

@@ -0,0 +1,47 @@
using GameCore.Input.Interfaces;
using Godot;
using GameCoreMath = GameCore.Math.Vector3;
namespace CryptonymThunder.Code.Services;
public class GodotInputService : IInputService
{
private Vector2 _mouseDeltaAccumulator = Vector2.Zero;
private const float MouseSensitivity = 0.002f;
public bool IsFiring { get; private set; }
public bool IsInteracting { get; private set; }
public bool IsJumping { get; private set; }
public GameCoreMath MoveDirection { get; private set; }
public GameCoreMath LookDirection { get; private set; }
public void HandleInputEvent(InputEvent e)
{
if (e is InputEventMouseMotion mouseMotion)
{
_mouseDeltaAccumulator += mouseMotion.Relative;
}
}
public void Update()
{
var godotInputVector = Input.GetVector("left", "right", "forward", "backward");
MoveDirection = new GameCoreMath(godotInputVector.X, 0f, godotInputVector.Y);
LookDirection = new GameCoreMath(
-_mouseDeltaAccumulator.Y * MouseSensitivity,
-_mouseDeltaAccumulator.X * MouseSensitivity,
0f);
_mouseDeltaAccumulator = Vector2.Zero;
IsJumping = Input.IsActionJustPressed("jump");
IsFiring = Input.IsActionPressed("fire");
IsInteracting = Input.IsActionPressed("interact");
}
public void LateUpdate()
{
LookDirection = GameCoreMath.Zero;
}
}

View File

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

View File

@@ -0,0 +1,59 @@
using System;
using CryptonymThunder.Code.Autoloads;
using CryptonymThunder.Code.Extensions;
using CryptonymThunder.Code.Presenters;
using GameCore.ECS;
using GameCore.ECS.Interfaces;
using Godot;
using GodotWorld = Godot.World3D;
using Vector3 = GameCore.Math.Vector3;
namespace CryptonymThunder.Code.Services;
public class GodotWorldQuery(GamePresenter ownerNode) : IWorldQuery
{
private readonly PresenterRegistry _presenterRegistry = ownerNode.GetNode<PresenterRegistry>("/root/PresenterRegistry");
private readonly GodotWorld _godotWorld = ((SceneTree)Engine.GetMainLoop()).Root.World3D;
public HitResult Raycast(Vector3 from, Vector3 to, Entity? ownerToExclude = null)
{
var spaceState = _godotWorld.DirectSpaceState;
var query = PhysicsRayQueryParameters3D.Create(from.ToGodot(), to.ToGodot());
query.CollisionMask = 1;
query.CollideWithBodies = true;
query.CollideWithAreas = false;
if (ownerToExclude.HasValue)
{
var ownerPresenter = ownerNode.GetPresenterNode(ownerToExclude.Value);
if (ownerPresenter != null)
{
query.Exclude = [((PhysicsBody3D)ownerPresenter).GetRid()];
}
}
var result = spaceState.IntersectRay(query);
if (result.Count > 0 && result["collider"].Obj is Node3D collider)
{
if (_presenterRegistry.TryGetEntity(collider.GetInstanceId(), out var hitEntity))
{
return new HitResult
{
DidHit = true,
HitEntity = hitEntity
};
}
}
return new HitResult { DidHit = false };
}
public Vector3 RotateVectorByYaw(Vector3 vector, float yawRadians)
{
var rotatedX = vector.X * (float)Math.Cos(yawRadians) + vector.Z * (float)Math.Sin(yawRadians);
var rotatedZ = -vector.X * (float)Math.Sin(yawRadians) + vector.Z * (float)Math.Cos(yawRadians);
return new Vector3(rotatedX, vector.Y, rotatedZ);
}
}

View File

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

13
Objects/bullet.tscn Normal file
View File

@@ -0,0 +1,13 @@
[gd_scene load_steps=3 format=3 uid="uid://i84teqsbrmff"]
[ext_resource type="Script" uid="uid://dl2awoy0hyruh" path="res://Code/Presenters/TransformPresenterComponent.cs" id="1_ktj6t"]
[sub_resource type="SphereMesh" id="SphereMesh_48nvk"]
radius = 0.1
height = 0.1
radial_segments = 8
rings = 8
[node name="Bullet" type="MeshInstance3D"]
mesh = SubResource("SphereMesh_48nvk")
script = ExtResource("1_ktj6t")

28
Objects/player.tscn Normal file
View File

@@ -0,0 +1,28 @@
[gd_scene load_steps=5 format=3 uid="uid://c576jiewfs5gj"]
[ext_resource type="Script" uid="uid://hkiny1ftv4r7" path="res://Code/Presenters/CharacterBody3DPresenter.cs" id="2_3y5cq"]
[ext_resource type="Script" uid="uid://crx03e8buoni3" path="res://Code/Presenters/CameraPresenterComponent.cs" id="3_2i4gt"]
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_y0qk3"]
[sub_resource type="CapsuleMesh" id="CapsuleMesh_3y5cq"]
[node name="Player" type="CharacterBody3D"]
script = ExtResource("2_3y5cq")
metadata/_custom_type_script = "uid://hkiny1ftv4r7"
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0028362, 0)
shape = SubResource("CapsuleShape3D_y0qk3")
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0028362, 0)
visible = false
mesh = SubResource("CapsuleMesh_3y5cq")
skeleton = NodePath("")
[node name="CameraPivot" type="Node3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5901337, 0)
script = ExtResource("3_2i4gt")
[node name="Camera3D" type="Camera3D" parent="CameraPivot"]

View File

@@ -0,0 +1,27 @@
[gd_resource type="Resource" script_class="EntityArchetype" load_steps=9 format=3 uid="uid://cfwsnjb2nob32"]
[ext_resource type="Script" uid="uid://df5wmj1jp2oy5" path="res://Code/Resources/PositionComponentResource.cs" id="1_p4pan"]
[ext_resource type="Script" uid="uid://coe688e2jkyjq" path="res://Code/Resources/EntityArchetype.cs" id="1_puol3"]
[ext_resource type="Script" uid="uid://t4j1urlupxxv" path="res://Code/Resources/VelocityComponentResource.cs" id="2_rcqc5"]
[ext_resource type="PackedScene" uid="uid://i84teqsbrmff" path="res://Objects/bullet.tscn" id="3_mwldp"]
[ext_resource type="Script" uid="uid://ddryrwjq33832" path="res://Code/Resources/ProjectileComponentResource.cs" id="3_rcqc5"]
[sub_resource type="Resource" id="Resource_56sml"]
script = ExtResource("1_p4pan")
metadata/_custom_type_script = "uid://df5wmj1jp2oy5"
[sub_resource type="Resource" id="Resource_573xv"]
script = ExtResource("2_rcqc5")
metadata/_custom_type_script = "uid://t4j1urlupxxv"
[sub_resource type="Resource" id="Resource_mwldp"]
script = ExtResource("3_rcqc5")
Speed = 1.0
Lifetime = 1.0
metadata/_custom_type_script = "uid://ddryrwjq33832"
[resource]
script = ExtResource("1_puol3")
Scene = ExtResource("3_mwldp")
ComponentResources = Array[Resource]([SubResource("Resource_56sml"), SubResource("Resource_573xv"), SubResource("Resource_mwldp")])
metadata/_custom_type_script = "uid://coe688e2jkyjq"

View File

@@ -0,0 +1,60 @@
[gd_resource type="Resource" script_class="EntityArchetype" load_steps=20 format=3 uid="uid://biev6ri5s8kyf"]
[ext_resource type="Script" uid="uid://dc7wq2ij5kwj5" path="res://Code/Resources/AttributeComponentResource.cs" id="1_0drlr"]
[ext_resource type="Script" uid="uid://y4cbuh2wxigy" path="res://Code/Resources/InputStateComponentResource.cs" id="2_7o5r3"]
[ext_resource type="Script" uid="uid://p4vr80n70vkt" path="res://Code/Resources/PlayerComponentResource.cs" id="3_l66rq"]
[ext_resource type="Script" uid="uid://df5wmj1jp2oy5" path="res://Code/Resources/PositionComponentResource.cs" id="4_efscl"]
[ext_resource type="Script" uid="uid://t4j1urlupxxv" path="res://Code/Resources/VelocityComponentResource.cs" id="5_55dod"]
[ext_resource type="Script" uid="uid://blm62f85g7icn" path="res://Code/Resources/RotationComponentResource.cs" id="6_8u8a8"]
[ext_resource type="Script" uid="uid://cdpbn8eiypfbd" path="res://Code/Resources/CharacterStateComponentResource.cs" id="7_m2ull"]
[ext_resource type="PackedScene" uid="uid://c576jiewfs5gj" path="res://Objects/player.tscn" id="8_0q1v5"]
[ext_resource type="Resource" uid="uid://tj3ojc3bl7d8" path="res://Resources/Weapons/basic_pistol.tres" id="8_l66rq"]
[ext_resource type="Script" uid="uid://bp7mufswr41w6" path="res://Code/Resources/WeaponComponentResource.cs" id="9_efscl"]
[ext_resource type="Script" uid="uid://coe688e2jkyjq" path="res://Code/Resources/EntityArchetype.cs" id="9_uue6s"]
[sub_resource type="Resource" id="Resource_d0bjv"]
script = ExtResource("1_0drlr")
BaseValues = Dictionary[int, float]({
0: 100.0,
1: 100.0,
3: 5.0,
4: 10.0,
5: 30.0,
6: 1.0
})
metadata/_custom_type_script = "uid://dc7wq2ij5kwj5"
[sub_resource type="Resource" id="Resource_l855d"]
script = ExtResource("2_7o5r3")
metadata/_custom_type_script = "uid://y4cbuh2wxigy"
[sub_resource type="Resource" id="Resource_00aki"]
script = ExtResource("3_l66rq")
metadata/_custom_type_script = "uid://p4vr80n70vkt"
[sub_resource type="Resource" id="Resource_5qvjo"]
script = ExtResource("4_efscl")
metadata/_custom_type_script = "uid://df5wmj1jp2oy5"
[sub_resource type="Resource" id="Resource_g7kif"]
script = ExtResource("5_55dod")
metadata/_custom_type_script = "uid://t4j1urlupxxv"
[sub_resource type="Resource" id="Resource_xqdar"]
script = ExtResource("6_8u8a8")
metadata/_custom_type_script = "uid://blm62f85g7icn"
[sub_resource type="Resource" id="Resource_xnm3i"]
script = ExtResource("7_m2ull")
metadata/_custom_type_script = "uid://cdpbn8eiypfbd"
[sub_resource type="Resource" id="Resource_55dod"]
script = ExtResource("9_efscl")
WeaponData = ExtResource("8_l66rq")
metadata/_custom_type_script = "uid://bp7mufswr41w6"
[resource]
script = ExtResource("9_uue6s")
Scene = ExtResource("8_0q1v5")
ComponentResources = Array[Resource]([SubResource("Resource_d0bjv"), SubResource("Resource_l855d"), SubResource("Resource_00aki"), SubResource("Resource_5qvjo"), SubResource("Resource_g7kif"), SubResource("Resource_xqdar"), SubResource("Resource_xnm3i"), SubResource("Resource_55dod")])
metadata/_custom_type_script = "uid://coe688e2jkyjq"

View File

@@ -0,0 +1,24 @@
[gd_resource type="Resource" script_class="WeaponResource" load_steps=6 format=3 uid="uid://tj3ojc3bl7d8"]
[ext_resource type="Script" uid="uid://cht6trljihvle" path="res://Code/Resources/Effects/FireProjectileEffectResource.cs" id="1_p2b4p"]
[ext_resource type="Script" uid="uid://hf0iut8o8do3" path="res://Code/Resources/WeaponResource.cs" id="1_qn35l"]
[ext_resource type="Script" uid="uid://btv24gsw1p850" path="res://Code/Resources/Effects/DamageEffectResource.cs" id="2_yt3rn"]
[sub_resource type="Resource" id="Resource_yt3rn"]
script = ExtResource("1_p2b4p")
ProjectileArchetypeId = "basic_bullet"
Count = 3
SpreadAngle = 5.7
ProjectileSpeed = 10.0
metadata/_custom_type_script = "uid://cht6trljihvle"
[sub_resource type="Resource" id="Resource_wqp4f"]
script = ExtResource("2_yt3rn")
metadata/_custom_type_script = "uid://btv24gsw1p850"
[resource]
script = ExtResource("1_qn35l")
FireRate = 10.0
OnFireEffects = Array[Object]([SubResource("Resource_yt3rn")])
OnHitEffects = Array[Object]([SubResource("Resource_wqp4f")])
metadata/_custom_type_script = "uid://hf0iut8o8do3"

View File

@@ -0,0 +1,12 @@
[gd_resource type="Resource" script_class="ArchetypeDatabase" load_steps=4 format=3 uid="uid://cr4nf1g4w3xye"]
[ext_resource type="Script" uid="uid://coe688e2jkyjq" path="res://Code/Resources/EntityArchetype.cs" id="1_pa128"]
[ext_resource type="Script" uid="uid://df10ksb6f0pjt" path="res://Code/Resources/ArchetypeDatabase.cs" id="2_7tiqc"]
[ext_resource type="Resource" uid="uid://cfwsnjb2nob32" path="res://Resources/Entities/basic_bullet.tres" id="2_n2q8x"]
[resource]
script = ExtResource("2_7tiqc")
Archetypes = Dictionary[String, ExtResource("1_pa128")]({
"basic_bullet": ExtResource("2_n2q8x")
})
metadata/_custom_type_script = "uid://df10ksb6f0pjt"

215
Scenes/game_world.tscn Normal file
View File

@@ -0,0 +1,215 @@
[gd_scene load_steps=20 format=4 uid="uid://bkvgcsb8d3v7p"]
[ext_resource type="Script" uid="uid://cfpm5p102f65x" path="res://Code/Presenters/GamePresenter.cs" id="1_qvgq0"]
[ext_resource type="Resource" uid="uid://biev6ri5s8kyf" path="res://Resources/Entities/player.tres" id="2_alii3"]
[ext_resource type="Resource" uid="uid://cr4nf1g4w3xye" path="res://Resources/entity_database.tres" id="2_hy2kt"]
[ext_resource type="Script" uid="uid://cb7vaw6xqjs1i" path="res://Code/Presenters/EntityPresenter.cs" id="5_d0bjv"]
[ext_resource type="Script" uid="uid://b6x8llipvutqs" path="res://Code/Presenters/SceneEntity.cs" id="5_f1ejf"]
[ext_resource type="Script" uid="uid://dc7wq2ij5kwj5" path="res://Code/Resources/AttributeComponentResource.cs" id="6_d0bjv"]
[ext_resource type="Script" uid="uid://uearpvfk21ym" path="res://Code/Resources/SimulationConfigResource.cs" id="11_xnm3i"]
[sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_ucfah"]
data = PackedVector3Array(-4.282257, -0.5, 4.977783, -4.282257, -0.5, -4.977783, -4.282257, 0.5, -4.977783, 4.282257, -0.5, -4.977783, -4.282257, -0.5, -4.977783, -4.282257, -0.5, 4.977783, -4.282257, 0.5, -4.977783, -4.282257, -0.5, -4.977783, 4.282257, -0.5, -4.977783, -4.282257, 0.5, -4.977783, -4.282257, 0.5, 4.977783, -4.282257, -0.5, 4.977783, -4.282257, -0.5, 4.977783, -4.282257, 0.5, 4.977783, 4.282257, 0.5, 4.977783, 4.282257, 0.5, 4.977783, -4.282257, 0.5, 4.977783, -4.282257, 0.5, -4.977783, -4.282257, -0.5, 4.977783, 4.282257, -0.5, 4.977783, 4.282257, -0.5, -4.977783, 4.282257, 0.5, 4.977783, 4.282257, -0.5, 4.977783, -4.282257, -0.5, 4.977783, 4.282257, -0.5, -4.977783, 4.282257, -0.5, 4.977783, 4.282257, 0.5, 4.977783, 4.282257, -0.5, -4.977783, 4.282257, 0.5, -4.977783, -4.282257, 0.5, -4.977783, -4.282257, 0.5, -4.977783, 4.282257, 0.5, -4.977783, 4.282257, 0.5, 4.977783, 4.282257, 0.5, 4.977783, 4.282257, 0.5, -4.977783, 4.282257, -0.5, -4.977783)
[sub_resource type="ArrayMesh" id="ArrayMesh_ucfah"]
_surfaces = [{
"aabb": AABB(-4.282257, -0.5, -4.977783, 8.564514, 1, 9.955566),
"attribute_data": PackedByteArray("AACAPwAAgD8AAIA/AAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/AAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/AAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/AAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/"),
"format": 34359738391,
"primitive": 3,
"uv_scale": Vector4(0, 0, 0, 0),
"vertex_count": 36,
"vertex_data": PackedByteArray("QAiJwAAAAL8ASp9AQAiJwAAAAL8ASp/AQAiJwAAAAD8ASp/AQAiJQAAAAL8ASp/AQAiJwAAAAL8ASp/AQAiJwAAAAL8ASp9AQAiJwAAAAD8ASp/AQAiJwAAAAL8ASp/AQAiJQAAAAL8ASp/AQAiJwAAAAD8ASp/AQAiJwAAAAD8ASp9AQAiJwAAAAL8ASp9AQAiJwAAAAL8ASp9AQAiJwAAAAD8ASp9AQAiJQAAAAD8ASp9AQAiJQAAAAD8ASp9AQAiJwAAAAD8ASp9AQAiJwAAAAD8ASp/AQAiJwAAAAL8ASp9AQAiJQAAAAL8ASp9AQAiJQAAAAL8ASp/AQAiJQAAAAD8ASp9AQAiJQAAAAL8ASp9AQAiJwAAAAL8ASp9AQAiJQAAAAL8ASp/AQAiJQAAAAL8ASp9AQAiJQAAAAD8ASp9AQAiJQAAAAL8ASp/AQAiJQAAAAD8ASp/AQAiJwAAAAD8ASp/AQAiJwAAAAD8ASp/AQAiJQAAAAD8ASp/AQAiJQAAAAD8ASp9AQAiJQAAAAD8ASp9AQAiJQAAAAD8ASp/AQAiJQAAAAL8ASp/AAAD/f/9//n8AAP9//3/+fwAA/3//f/5//38AAP//AAD/fwAA//8AAP9/AAD//wAA/////wAA/z//////AAD/P/////8AAP8/AAD/f/9//n8AAP9//3/+fwAA/3//f/5//3//fwAA/z//f/9/AAD/P/9//38AAP8//3//////AAD/f/////8AAP9//////wAA/38AAP//AAD/fwAA//8AAP9/AAD//wAA/3//fwAA/z//f/9/AAD/P/9//38AAP8/////f/9//n////9//3/+f////3//f/5//////wAA/z//////AAD/P/////8AAP8//3//////AAD/f/////8AAP9//////wAA////f/9//n////9//3/+f////3//f/5/")
}]
[sub_resource type="SphereMesh" id="SphereMesh_27os8"]
[sub_resource type="CylinderMesh" id="CylinderMesh_rr1si"]
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_qvgq0"]
sky_horizon_color = Color(0.66224277, 0.6717428, 0.6867428, 1)
ground_horizon_color = Color(0.66224277, 0.6717428, 0.6867428, 1)
[sub_resource type="Sky" id="Sky_alii3"]
sky_material = SubResource("ProceduralSkyMaterial_qvgq0")
[sub_resource type="Environment" id="Environment_hy2kt"]
background_mode = 2
sky = SubResource("Sky_alii3")
tonemap_mode = 2
glow_enabled = true
[sub_resource type="Resource" id="Resource_f4pnd"]
script = ExtResource("11_xnm3i")
metadata/_custom_type_script = "uid://uearpvfk21ym"
[sub_resource type="BoxShape3D" id="BoxShape3D_hy2kt"]
[sub_resource type="BoxMesh" id="BoxMesh_p4c8d"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_f1ejf"]
albedo_color = Color(0.34509805, 1, 1, 1)
[sub_resource type="Resource" id="Resource_27os8"]
script = ExtResource("6_d0bjv")
BaseValues = Dictionary[int, float]({
0: 50.0,
1: 50.0
})
metadata/_custom_type_script = "uid://dc7wq2ij5kwj5"
[node name="GameWorld" type="Node3D"]
[node name="Geometry" type="Node" parent="."]
[node name="CSGBox3D" type="CSGBox3D" parent="Geometry"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.23013306, 0, 0.34545898)
visible = false
size = Vector3(8.564514, 1, 9.955566)
[node name="CSGBakedMeshInstance3D" type="StaticBody3D" parent="Geometry"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.23013306, -1.5645537, 0.34545898)
[node name="CSGBakedCollisionShape3D" type="CollisionShape3D" parent="Geometry/CSGBakedMeshInstance3D"]
shape = SubResource("ConcavePolygonShape3D_ucfah")
[node name="CSGBakedMeshInstance3D2" type="MeshInstance3D" parent="Geometry/CSGBakedMeshInstance3D"]
mesh = SubResource("ArrayMesh_ucfah")
skeleton = NodePath("../../..")
[node name="MeshInstance3D" type="MeshInstance3D" parent="Geometry"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -7.746681, 0, 0)
mesh = SubResource("SphereMesh_27os8")
skeleton = NodePath("../..")
[node name="MeshInstance3D2" type="MeshInstance3D" parent="Geometry"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -7.746681, 0, 6.6297135)
mesh = SubResource("SphereMesh_27os8")
skeleton = NodePath("../..")
[node name="MeshInstance3D3" type="MeshInstance3D" parent="Geometry"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -7.746681, 0, -4.5654445)
mesh = SubResource("SphereMesh_27os8")
skeleton = NodePath("../..")
[node name="MeshInstance3D4" type="MeshInstance3D" parent="Geometry"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5.4873514, 0, 0)
mesh = SubResource("CylinderMesh_rr1si")
[node name="MeshInstance3D5" type="MeshInstance3D" parent="Geometry"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5.4873514, 0, -3.6716075)
mesh = SubResource("CylinderMesh_rr1si")
[node name="MeshInstance3D6" type="MeshInstance3D" parent="Geometry"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5.4873514, 0, 2.8093686)
mesh = SubResource("CylinderMesh_rr1si")
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_hy2kt")
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
transform = Transform3D(-0.8660254, -0.43301278, 0.25, 0, 0.49999997, 0.86602545, -0.50000006, 0.75, -0.43301266, 0, 0, 0)
shadow_enabled = true
[node name="GamePresenter" type="Node" parent="."]
script = ExtResource("1_qvgq0")
ArchetypesDatabase = ExtResource("2_hy2kt")
PlayerArchetype = ExtResource("2_alii3")
SimulationConfig = SubResource("Resource_f4pnd")
metadata/_custom_type_script = "uid://cfpm5p102f65x"
[node name="Enemy" type="StaticBody3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.6186395, 0, -6.099209)
script = ExtResource("5_d0bjv")
[node name="CollisionShape3D" type="CollisionShape3D" parent="Enemy"]
shape = SubResource("BoxShape3D_hy2kt")
[node name="MeshInstance3D" type="MeshInstance3D" parent="Enemy"]
mesh = SubResource("BoxMesh_p4c8d")
surface_material_override/0 = SubResource("StandardMaterial3D_f1ejf")
[node name="SceneEntity" type="Node" parent="Enemy" groups=["SceneEntities"]]
script = ExtResource("5_f1ejf")
ComponentResources = Array[Resource]([SubResource("Resource_27os8")])
metadata/_custom_type_script = "uid://b6x8llipvutqs"
[node name="Enemy2" type="StaticBody3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3.8842628, 0, -6.099209)
script = ExtResource("5_d0bjv")
[node name="CollisionShape3D" type="CollisionShape3D" parent="Enemy2"]
shape = SubResource("BoxShape3D_hy2kt")
[node name="MeshInstance3D" type="MeshInstance3D" parent="Enemy2"]
mesh = SubResource("BoxMesh_p4c8d")
surface_material_override/0 = SubResource("StandardMaterial3D_f1ejf")
[node name="SceneEntity" type="Node" parent="Enemy2" groups=["SceneEntities"]]
script = ExtResource("5_f1ejf")
ComponentResources = Array[Resource]([SubResource("Resource_27os8")])
metadata/_custom_type_script = "uid://b6x8llipvutqs"
[node name="Enemy3" type="StaticBody3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2.4516838, 0, -6.099209)
script = ExtResource("5_d0bjv")
[node name="CollisionShape3D" type="CollisionShape3D" parent="Enemy3"]
shape = SubResource("BoxShape3D_hy2kt")
[node name="MeshInstance3D" type="MeshInstance3D" parent="Enemy3"]
mesh = SubResource("BoxMesh_p4c8d")
surface_material_override/0 = SubResource("StandardMaterial3D_f1ejf")
[node name="SceneEntity" type="Node" parent="Enemy3" groups=["SceneEntities"]]
script = ExtResource("5_f1ejf")
ComponentResources = Array[Resource]([SubResource("Resource_27os8")])
metadata/_custom_type_script = "uid://b6x8llipvutqs"
[node name="Enemy4" type="StaticBody3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.3889283, 0, -6.099209)
script = ExtResource("5_d0bjv")
[node name="CollisionShape3D" type="CollisionShape3D" parent="Enemy4"]
shape = SubResource("BoxShape3D_hy2kt")
[node name="MeshInstance3D" type="MeshInstance3D" parent="Enemy4"]
mesh = SubResource("BoxMesh_p4c8d")
surface_material_override/0 = SubResource("StandardMaterial3D_f1ejf")
[node name="SceneEntity" type="Node" parent="Enemy4" groups=["SceneEntities"]]
script = ExtResource("5_f1ejf")
ComponentResources = Array[Resource]([SubResource("Resource_27os8")])
metadata/_custom_type_script = "uid://b6x8llipvutqs"
[node name="Enemy5" type="StaticBody3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.068998575, 0, -6.099209)
script = ExtResource("5_d0bjv")
[node name="CollisionShape3D" type="CollisionShape3D" parent="Enemy5"]
shape = SubResource("BoxShape3D_hy2kt")
[node name="MeshInstance3D" type="MeshInstance3D" parent="Enemy5"]
mesh = SubResource("BoxMesh_p4c8d")
surface_material_override/0 = SubResource("StandardMaterial3D_f1ejf")
[node name="SceneEntity" type="Node" parent="Enemy5" groups=["SceneEntities"]]
script = ExtResource("5_f1ejf")
ComponentResources = Array[Resource]([SubResource("Resource_27os8")])
metadata/_custom_type_script = "uid://b6x8llipvutqs"
[node name="Enemy6" type="StaticBody3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.1687164, 0, -6.099209)
script = ExtResource("5_d0bjv")
[node name="CollisionShape3D" type="CollisionShape3D" parent="Enemy6"]
shape = SubResource("BoxShape3D_hy2kt")
[node name="MeshInstance3D" type="MeshInstance3D" parent="Enemy6"]
mesh = SubResource("BoxMesh_p4c8d")
surface_material_override/0 = SubResource("StandardMaterial3D_f1ejf")
[node name="SceneEntity" type="Node" parent="Enemy6" groups=["SceneEntities"]]
script = ExtResource("5_f1ejf")
ComponentResources = Array[Resource]([SubResource("Resource_27os8")])
metadata/_custom_type_script = "uid://b6x8llipvutqs"

13
cryptonym-thunder.csproj Normal file
View File

@@ -0,0 +1,13 @@
<Project Sdk="Godot.NET.Sdk/4.5.0">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework Condition=" '$(GodotTargetPlatform)' == 'android' ">net9.0</TargetFramework>
<EnableDynamicLoading>true</EnableDynamicLoading>
<RootNamespace>cryptonymthunder</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Reference Include="GameCore">
<HintPath>..\BrickFramework\GameCore\bin\Debug\net8.0\GameCore.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

19
cryptonym-thunder.sln Normal file
View File

@@ -0,0 +1,19 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "cryptonym-thunder", "cryptonym-thunder.csproj", "{FA84E88F-33AD-4744-BE22-A61FBD7395EA}"
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
{FA84E88F-33AD-4744-BE22-A61FBD7395EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FA84E88F-33AD-4744-BE22-A61FBD7395EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FA84E88F-33AD-4744-BE22-A61FBD7395EA}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU
{FA84E88F-33AD-4744-BE22-A61FBD7395EA}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU
{FA84E88F-33AD-4744-BE22-A61FBD7395EA}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU
{FA84E88F-33AD-4744-BE22-A61FBD7395EA}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU
EndGlobalSection
EndGlobal

1
icon.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128"><rect width="124" height="124" x="2" y="2" fill="#363d52" stroke="#212532" stroke-width="4" rx="14"/><g fill="#fff" transform="translate(12.322 12.322)scale(.101)"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042" transform="translate(12.322 12.322)scale(.101)"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg>

After

Width:  |  Height:  |  Size: 995 B

43
icon.svg.import Normal file
View File

@@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cnihftpgobl1c"
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://icon.svg"
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.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
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

79
project.godot Normal file
View File

@@ -0,0 +1,79 @@
; 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=5
[application]
config/name="cryptonym-thunder"
run/main_scene="uid://bkvgcsb8d3v7p"
config/features=PackedStringArray("4.5", "C#", "Forward Plus")
config/icon="res://icon.svg"
[autoload]
PresenterRegistry="*res://Code/Autoloads/PresenterRegistry.cs"
[dotnet]
project/assembly_name="cryptonym-thunder"
[file_customization]
folder_colors={
"res://Code/": "blue",
"res://Objects/": "orange",
"res://Scenes/": "green"
}
[global_group]
SceneEntities=""
[input]
left={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"location":0,"echo":false,"script":null)
]
}
right={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null)
]
}
forward={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null)
]
}
backward={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null)
]
}
debug_damage={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":70,"key_label":0,"unicode":102,"location":0,"echo":false,"script":null)
]
}
jump={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null)
]
}
interact={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":69,"key_label":0,"unicode":101,"location":0,"echo":false,"script":null)
]
}
fire={
"deadzone": 0.2,
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":1,"position":Vector2(584, 16),"global_position":Vector2(593, 64),"factor":1.0,"button_index":1,"canceled":false,"pressed":true,"double_click":false,"script":null)
]
}