WIP added navigation component, worked on ground motion component, added hexcell line to and distance functions.
parent
3ed113dd41
commit
c7349f4cee
39
HexCell.cs
39
HexCell.cs
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Godot;
|
||||
using Array = Godot.Collections.Array;
|
||||
|
||||
|
@ -45,6 +46,14 @@ public class HexCell : Resource
|
|||
CubeCoords = other.CubeCoords;
|
||||
}
|
||||
|
||||
public static HexCell FromOffsetCoords(Vector2 offsetCoords)
|
||||
{
|
||||
HexCell result = new HexCell();
|
||||
result.OffsetCoords = offsetCoords;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Vector3 _cubeCoords;
|
||||
|
||||
public Vector3 CubeCoords
|
||||
|
@ -123,8 +132,36 @@ public class HexCell : Resource
|
|||
return rounded;
|
||||
}
|
||||
|
||||
public HexCell getAdjacent(Vector3 dir)
|
||||
public HexCell GetAdjacent(Vector3 dir)
|
||||
{
|
||||
return new HexCell(this.CubeCoords + dir);
|
||||
}
|
||||
|
||||
public int DistanceTo(HexCell target)
|
||||
{
|
||||
return (int)(
|
||||
Mathf.Abs(_cubeCoords.x - target.CubeCoords.x)
|
||||
+ Mathf.Abs(_cubeCoords.y - target.CubeCoords.y)
|
||||
+ Mathf.Abs(_cubeCoords.z - target.CubeCoords.z)
|
||||
) / 2;
|
||||
}
|
||||
|
||||
public HexCell[] LineTo(HexCell target)
|
||||
{
|
||||
HexCell nudgedTarget = new HexCell();
|
||||
nudgedTarget.CubeCoords = target.CubeCoords + new Vector3(1.0e-6f, 2.0e-6f, -3.0e-6f);
|
||||
int steps = DistanceTo(target);
|
||||
|
||||
HexCell[] path = new HexCell[steps + 1];
|
||||
|
||||
foreach (int dist in Enumerable.Range(0, steps))
|
||||
{
|
||||
path[dist] = new HexCell();
|
||||
path[dist].CubeCoords = CubeCoords.LinearInterpolate(nudgedTarget.CubeCoords, (float)dist / steps);
|
||||
}
|
||||
|
||||
path[steps] = target;
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
|
@ -10,40 +10,84 @@ public class GroundMotionComponent
|
|||
{
|
||||
public float Accel = 50;
|
||||
public float Damping = 0.2f;
|
||||
public float MaxSpeed = 2;
|
||||
public float MaxSpeed = 8;
|
||||
|
||||
public void PhysicsProcess(float delta, Entity entity, Vector3 target_position)
|
||||
|
||||
private void CalcPlaneVelocity(float delta, Entity entity, Vector3 targetPosition)
|
||||
{
|
||||
Vector2 plane_target_vector = new Vector2(target_position.x - entity.GlobalTranslation.x,
|
||||
target_position.z - entity.GlobalTranslation.z);
|
||||
float distance_error = plane_target_vector.Length();
|
||||
|
||||
if (distance_error < 0.01)
|
||||
Vector2 planeTargetVector = new Vector2(targetPosition.x - entity.GlobalTranslation.x,
|
||||
targetPosition.z - entity.GlobalTranslation.z);
|
||||
float targetDistance = planeTargetVector.Length();
|
||||
Vector2 planeTargetDirection = planeTargetVector / targetDistance;
|
||||
|
||||
Vector2 planeVelocity = new Vector2(entity.Velocity.x, entity.Velocity.z);
|
||||
// GD.Print("-- Step: distance: " + targetDistance + " dir: " + planeTargetDirection + " speed: " + planeVelocity.Length() + " vel dir: " + planeVelocity.Normalized());
|
||||
planeVelocity -= planeVelocity * Damping;
|
||||
// GD.Print(" damp : speed: " + planeVelocity.Length() + " vel dir: " + planeVelocity.Normalized());
|
||||
|
||||
if (targetDistance < 0.01)
|
||||
{
|
||||
entity.Velocity = Vector3.Zero;
|
||||
planeVelocity = Vector2.Zero;
|
||||
} else {
|
||||
Vector2 plane_velocity = new Vector2(entity.Velocity.x, entity.Velocity.z);
|
||||
plane_velocity = plane_velocity + plane_target_vector / distance_error * Accel * delta;
|
||||
planeVelocity = planeVelocity.Length() * planeTargetDirection + planeTargetDirection * Accel * delta;
|
||||
// GD.Print(" accel: speed: " + planeVelocity.Length() + " vel dir: " + planeVelocity.Normalized());
|
||||
|
||||
float projected_step = plane_target_vector.Dot(plane_velocity * delta);
|
||||
GD.Print("Projected step: " + projected_step);
|
||||
if (projected_step > 1)
|
||||
float projectedStep = planeTargetDirection.Dot(planeVelocity * delta);
|
||||
// GD.Print(" Projected step: " + projectedStep + " Speed: " + planeVelocity.Length() + " delta: " + delta);
|
||||
if (projectedStep > targetDistance)
|
||||
{
|
||||
plane_velocity /= projected_step;
|
||||
planeVelocity *= targetDistance / projectedStep;
|
||||
projectedStep = planeTargetDirection.Dot(planeVelocity * delta);
|
||||
// GD.Print(" corr speed: " + planeVelocity.Length() + " step: " + projectedStep);
|
||||
}
|
||||
|
||||
float plane_speed = plane_velocity.Length();
|
||||
if (plane_speed > MaxSpeed)
|
||||
|
||||
float planeSpeed = planeVelocity.Length();
|
||||
if (planeSpeed > MaxSpeed)
|
||||
{
|
||||
plane_velocity *= MaxSpeed / plane_speed;
|
||||
planeVelocity *= MaxSpeed / planeSpeed;
|
||||
}
|
||||
|
||||
entity.Velocity = new Vector3(
|
||||
plane_velocity.x, 0, plane_velocity.y);
|
||||
}
|
||||
|
||||
entity.Velocity.x -= entity.Velocity.x * Damping;
|
||||
entity.Velocity.z -= entity.Velocity.z * Damping;
|
||||
entity.Velocity = new Vector3(planeVelocity.x, entity.Velocity.y, planeVelocity.y);
|
||||
}
|
||||
|
||||
|
||||
private void CalcVerticalVelocity(float delta, Entity entity, TileWorld tileWorld)
|
||||
{
|
||||
Vector3 entityVelocity = entity.Velocity;
|
||||
|
||||
Vector2 currentTile = tileWorld.WorldToOffsetCoords(entity.GlobalTransform.origin);
|
||||
Vector2 nextTile = tileWorld.WorldToOffsetCoords(entity.GlobalTransform.origin + entityVelocity * delta);
|
||||
|
||||
if (nextTile != currentTile)
|
||||
{
|
||||
float currentHeight = tileWorld.GetHeightAtOffset(currentTile);
|
||||
float nextHeight = tileWorld.GetHeightAtOffset(nextTile);
|
||||
|
||||
bool isOnFloor = entity.IsOnFloor();
|
||||
|
||||
if (nextHeight - entity.GlobalTransform.origin.y > 0.1)
|
||||
{
|
||||
GD.Print("Jump!");
|
||||
entityVelocity.y = 10;
|
||||
}
|
||||
}
|
||||
|
||||
entityVelocity.y -= 9.81f * delta;
|
||||
|
||||
entity.Velocity = entityVelocity;
|
||||
}
|
||||
|
||||
|
||||
public void PhysicsProcess(float delta, Entity entity, Vector3 targetPosition, TileWorld tileWorld)
|
||||
{
|
||||
CalcPlaneVelocity(delta, entity, targetPosition);
|
||||
|
||||
CalcVerticalVelocity(delta, entity, tileWorld);
|
||||
|
||||
Vector3 prePhysicsVelocity = entity.Velocity;
|
||||
entity.Velocity = entity.MoveAndSlide(entity.Velocity);
|
||||
GD.Print("Pre : speed: " + prePhysicsVelocity.Length() + " Velocity: " + prePhysicsVelocity);
|
||||
GD.Print("Post: speed: " + entity.Velocity.Length() + " Velocity: " + entity.Velocity);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Godot;
|
||||
using Vector2 = Godot.Vector2;
|
||||
using Vector3 = Godot.Vector3;
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public class NavigationComponent
|
||||
{
|
||||
public Vector3 currentGoalWorld;
|
||||
public Vector2 currentGoalOffset;
|
||||
public List<Vector2> pathOffsetCoords;
|
||||
public HexCell[] path;
|
||||
|
||||
private HexGrid _hexGrid;
|
||||
|
||||
public void Plan(Vector3 currentPositionWorld, Vector3 targetPositionWorld, TileWorld tileWorld)
|
||||
{
|
||||
if ((targetPositionWorld - currentGoalWorld).LengthSquared() < 0.01)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
currentGoalWorld = targetPositionWorld;
|
||||
Vector2 currentPositionOffset = tileWorld.WorldToOffsetCoords(currentPositionWorld);
|
||||
Vector2 currentGoalOffset = tileWorld.WorldToOffsetCoords(targetPositionWorld);
|
||||
|
||||
HexCell currentCell = new HexCell();
|
||||
currentCell.OffsetCoords = currentPositionOffset;
|
||||
|
||||
HexCell targetCell = new HexCell();
|
||||
targetCell.OffsetCoords = currentGoalOffset;
|
||||
|
||||
path = currentCell.LineTo(targetCell);
|
||||
|
||||
pathOffsetCoords = new List<Vector2>();
|
||||
foreach (HexCell cell in path)
|
||||
{
|
||||
pathOffsetCoords.Append(cell.OffsetCoords);
|
||||
}
|
||||
|
||||
currentGoalOffset = pathOffsetCoords[1];
|
||||
}
|
||||
}
|
|
@ -3,18 +3,10 @@ using System;
|
|||
|
||||
public class Entity : KinematicBody
|
||||
{
|
||||
public Vector3 Position = Vector3.Zero;
|
||||
public Quat Orientation = Quat.Identity;
|
||||
public Vector3 Velocity { get; set; } = Vector3.Zero;
|
||||
public float RotationalVelocity { get; set; } = 0;
|
||||
|
||||
public Vector3 Velocity = Vector3.Zero;
|
||||
public float RotationalVelocity = 0;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
}
|
||||
|
||||
public override void _Process(float _delta)
|
||||
{
|
||||
Velocity = MoveAndSlide(Velocity);
|
||||
}
|
||||
}
|
|
@ -12,11 +12,13 @@ public class Player : Entity
|
|||
private WorldInfoComponent _worldInfo;
|
||||
private Vector2 _offsetCoord = Vector2.Zero;
|
||||
private GroundMotionComponent _groundMotion;
|
||||
private NavigationComponent _navigationComponent;
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
_groundMotion = new GroundMotionComponent();
|
||||
_navigationComponent = new NavigationComponent();
|
||||
|
||||
_movable = (MovableComponent)FindNode("Movable", false);
|
||||
if (_movable != null)
|
||||
|
@ -33,9 +35,27 @@ public class Player : Entity
|
|||
public override void _PhysicsProcess(float delta)
|
||||
{
|
||||
base._PhysicsProcess(delta);
|
||||
_groundMotion.PhysicsProcess(delta, this, TargetPosition);
|
||||
|
||||
// update navigation target here
|
||||
|
||||
// update physics target
|
||||
Vector3 targetPosition =
|
||||
_worldInfo.TileWorld.GetTileWorldCenterFromOffset(_navigationComponent.currentGoalOffset);
|
||||
|
||||
// compute physics movement
|
||||
_groundMotion.PhysicsProcess(delta, this, targetPosition, _worldInfo.TileWorld);
|
||||
}
|
||||
|
||||
|
||||
public override void _Process(float delta)
|
||||
{
|
||||
if ((_navigationComponent.currentGoalWorld - TargetPosition).LengthSquared() > 0.01)
|
||||
{
|
||||
_navigationComponent.Plan(GlobalTransform.origin, TargetPosition, _worldInfo.TileWorld);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void OnPositionUpdated(Vector3 newPosition)
|
||||
{
|
||||
if (_worldInfo != null)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[gd_scene load_steps=15 format=2]
|
||||
[gd_scene load_steps=17 format=2]
|
||||
|
||||
[ext_resource path="res://scenes/AdaptiveWorldStream.cs" type="Script" id=1]
|
||||
[ext_resource path="res://assets/CreatusPiratePack/characters/Pirate1final_0.01.glb" type="PackedScene" id=2]
|
||||
|
@ -10,6 +10,14 @@
|
|||
[ext_resource path="res://components/MovableComponent.cs" type="Script" id=8]
|
||||
[ext_resource path="res://scenes/TileWorld.cs" type="Script" id=9]
|
||||
|
||||
[sub_resource type="OpenSimplexNoise" id=10]
|
||||
period = 39.6
|
||||
|
||||
[sub_resource type="NoiseTexture" id=11]
|
||||
width = 100
|
||||
height = 100
|
||||
noise = SubResource( 10 )
|
||||
|
||||
[sub_resource type="CubeMesh" id=1]
|
||||
size = Vector3( 1, 1, 1 )
|
||||
|
||||
|
@ -183,8 +191,9 @@ text = "0"
|
|||
[node name="WorldTextureRect" type="TextureRect" parent="Control"]
|
||||
margin_left = 1.0
|
||||
margin_top = 300.0
|
||||
margin_right = 101.0
|
||||
margin_bottom = 400.0
|
||||
margin_right = 513.0
|
||||
margin_bottom = 812.0
|
||||
texture = SubResource( 11 )
|
||||
|
||||
[node name="StreamContainer" type="Spatial" parent="."]
|
||||
script = ExtResource( 4 )
|
||||
|
|
|
@ -60,8 +60,8 @@ public class TileWorld : Spatial
|
|||
|
||||
noise_generator.Seed = -1626828106;
|
||||
noise_generator.Octaves = 3;
|
||||
noise_generator.Period = 5;
|
||||
noise_generator.Persistence = 0.5f;
|
||||
noise_generator.Period = 20;
|
||||
noise_generator.Persistence = 0.1f;
|
||||
noise_generator.Lacunarity = 2;
|
||||
|
||||
Heightmap.CopyFrom(noise_generator.GetImage((int)Size.x, (int)Size.y, null));
|
||||
|
@ -117,6 +117,17 @@ public class TileWorld : Spatial
|
|||
return _hexGrid.GetHexAt(new Vector2(world_coord.x, world_coord.z)).OffsetCoords;
|
||||
}
|
||||
|
||||
|
||||
public Vector3 GetTileWorldCenterFromOffset(Vector2 offset_coord)
|
||||
{
|
||||
Vector2 tileCenter = _hexGrid.GetHexCenterFromOffset(offset_coord);
|
||||
|
||||
return new Vector3(
|
||||
tileCenter.x,
|
||||
GetHeightAtOffset(offset_coord),
|
||||
tileCenter.y);
|
||||
}
|
||||
|
||||
// // Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
// public override void _Process(float delta)
|
||||
// {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
using System;
|
||||
using Godot;
|
||||
using GoDotTest;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
public class HexCellTests : TestClass
|
||||
{
|
||||
|
@ -88,21 +90,113 @@ public class HexCellTests : TestClass
|
|||
HexCell cell = new HexCell(new Vector2(1, 2));
|
||||
|
||||
// adjacent
|
||||
HexCell otherCell = cell.getAdjacent(HexCell.DIR_N);
|
||||
HexCell otherCell = cell.GetAdjacent(HexCell.DIR_N);
|
||||
Debug.Assert(otherCell.AxialCoords == new Vector2(1, 3));
|
||||
otherCell = cell.getAdjacent(HexCell.DIR_NE);
|
||||
otherCell = cell.GetAdjacent(HexCell.DIR_NE);
|
||||
Debug.Assert(otherCell.AxialCoords == new Vector2(2, 2));
|
||||
otherCell = cell.getAdjacent(HexCell.DIR_SE);
|
||||
otherCell = cell.GetAdjacent(HexCell.DIR_SE);
|
||||
Debug.Assert(otherCell.AxialCoords == new Vector2(2, 1));
|
||||
otherCell = cell.getAdjacent(HexCell.DIR_S);
|
||||
otherCell = cell.GetAdjacent(HexCell.DIR_S);
|
||||
Debug.Assert(otherCell.AxialCoords == new Vector2(1, 1));
|
||||
otherCell = cell.getAdjacent(HexCell.DIR_SW);
|
||||
otherCell = cell.GetAdjacent(HexCell.DIR_SW);
|
||||
Debug.Assert(otherCell.AxialCoords == new Vector2(0, 2));
|
||||
otherCell = cell.getAdjacent(HexCell.DIR_NW);
|
||||
otherCell = cell.GetAdjacent(HexCell.DIR_NW);
|
||||
Debug.Assert(otherCell.AxialCoords == new Vector2(0, 3));
|
||||
|
||||
// not really adjacent
|
||||
otherCell = cell.getAdjacent(new Vector3(-3, -3, 6));
|
||||
otherCell = cell.GetAdjacent(new Vector3(-3, -3, 6));
|
||||
Debug.Assert(otherCell.AxialCoords == new Vector2(-2, -1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDistance()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
cell.OffsetCoords = new Vector2(1, 2);
|
||||
|
||||
Debug.Assert(cell.DistanceTo(new HexCell(new Vector2(0, 0))) == 3);
|
||||
Debug.Assert(cell.DistanceTo(new HexCell(new Vector2(3, 4))) == 4);
|
||||
Debug.Assert(cell.DistanceTo(new HexCell(new Vector2(-1, -1))) == 5);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void TestLineTo()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
cell.OffsetCoords = new Vector2(1, 2);
|
||||
|
||||
HexCell[] path = cell.LineTo(new HexCell(5, 2));
|
||||
|
||||
HexCell[] pathExpected =
|
||||
{
|
||||
new HexCell(1, 2),
|
||||
new HexCell(2, 2),
|
||||
new HexCell(3, 2),
|
||||
new HexCell(4, 2),
|
||||
new HexCell(5, 2)
|
||||
};
|
||||
|
||||
Debug.Assert(path.Length == pathExpected.Length);
|
||||
|
||||
foreach (int index in Enumerable.Range(0, path.Length))
|
||||
{
|
||||
Debug.Assert(path[index].AxialCoords == pathExpected[index].AxialCoords);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void TestLineToAngled()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
cell.OffsetCoords = new Vector2(1, 2);
|
||||
|
||||
HexCell[] path = cell.LineTo(new HexCell(5, 4));
|
||||
|
||||
HexCell[] pathExpected =
|
||||
{
|
||||
new HexCell(1, 2),
|
||||
new HexCell(2, 2),
|
||||
new HexCell(2, 3),
|
||||
new HexCell(3, 3),
|
||||
new HexCell(4, 3),
|
||||
new HexCell(4, 4),
|
||||
new HexCell(5, 4)
|
||||
};
|
||||
|
||||
Debug.Assert(path.Length == pathExpected.Length);
|
||||
|
||||
foreach (int index in Enumerable.Range(0, path.Length))
|
||||
{
|
||||
Debug.Assert(path[index].AxialCoords == pathExpected[index].AxialCoords);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void TestLineEdge()
|
||||
{
|
||||
HexCell cell = new HexCell();
|
||||
cell.OffsetCoords = new Vector2(1, 2);
|
||||
|
||||
HexCell[] path = cell.LineTo(new HexCell(3, 4));
|
||||
|
||||
HexCell[] pathExpected =
|
||||
{
|
||||
new HexCell(1, 2),
|
||||
new HexCell(2, 2),
|
||||
new HexCell(2, 3),
|
||||
new HexCell(2, 4),
|
||||
new HexCell(3, 4)
|
||||
};
|
||||
|
||||
Debug.Assert(path.Length == pathExpected.Length);
|
||||
|
||||
foreach (int index in Enumerable.Range(0, path.Length))
|
||||
{
|
||||
Debug.Print("index: " + index + " path: " + path[index].AxialCoords + " expected: " + pathExpected[index].AxialCoords);
|
||||
Debug.Assert(path[index].AxialCoords == pathExpected[index].AxialCoords);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue