Compare commits

...

25 commits

Author SHA1 Message Date
134d897e51 one down two more take it's place 2024-11-23 16:51:50 -05:00
6eb4f60b8f less long press 2024-11-23 16:47:40 -05:00
877107a935 less wrong display preference 2024-11-23 16:46:53 -05:00
f287485d93 v++ 2024-11-23 16:31:43 -05:00
a27dc1cb53 hold select to skip intro 2024-11-23 16:30:51 -05:00
8772be83cc intro manual stepping override 2024-11-23 16:29:08 -05:00
5388e34d61 intro data 2024-11-23 16:27:16 -05:00
3a22e80c2a just one btn(resume) in menu rn 2024-11-23 16:27:04 -05:00
04afda9ba9 back for toggling menu and select 2024-11-23 16:26:40 -05:00
59a1cef9af handle menu conditional logic pause in program 2024-11-23 16:25:07 -05:00
dce6cf6c14 select(trigger or the a btn) and back btn for consistent understandable input across devices 2024-11-23 16:24:18 -05:00
5b69e88859 box scale in to be refactored later 2024-11-23 16:22:49 -05:00
b6794508f6 design notes 2024-11-23 16:21:07 -05:00
eeafaec61e step time limits 2024-11-23 12:40:01 -05:00
23f81af2ed prevent backtracking 2024-11-22 07:15:12 -05:00
64e7b2ea2f viable step gate 2024-11-22 07:14:30 -05:00
4762ebc184 face override hierarchy system with new face to indicate grow buffer > 0 2024-11-21 15:53:05 -05:00
91b91d9a4f integrate vcam into core application loop 2024-11-21 15:41:42 -05:00
57970e7c72 ignore recorded frames 2024-11-21 15:40:34 -05:00
be291f1d37 clear out bg for transparent recordings 2024-11-21 15:40:17 -05:00
a4516dd5d6 virtual cam for recording frames in game 2024-11-21 15:39:52 -05:00
a234c5fd22 render hands if not in mixed reality 2024-11-21 15:20:10 -05:00
1cc71b113b formatting fixes 2024-11-21 15:19:32 -05:00
35e3a813f2 scale in box at start using game time 2024-11-14 13:51:06 -05:00
94bad62aa6 in game/box time 2024-11-14 13:50:18 -05:00
8 changed files with 181 additions and 55 deletions

1
.gitignore vendored
View file

@ -7,6 +7,7 @@ bin/
obj/ obj/
Raw/ Raw/
_frames/
.vscode .vscode
anchors.txt anchors.txt

View file

@ -2,8 +2,8 @@
<manifest <manifest
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
package="com.dofdev.snake" package="com.dofdev.snake"
android:versionCode="17" android:versionCode="29"
android:versionName="1.27" android:versionName="1.32"
android:installLocation="auto" android:installLocation="auto"
> >
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="32" /> <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="32" />

View file

@ -62,7 +62,7 @@ todo
fun to play daily for a couple weeks or so fun to play daily for a couple weeks or so
playable with a half engaging vid or conversation in the background playable with a half engaging vid or conversation in the background
my tempo my tempo (zen mode *after initial release*)
on l_con tap (a) btn to step, and repeatedly to set tempo on l_con tap (a) btn to step, and repeatedly to set tempo
once a tempo has been set you can stop tapping and you'll coast at that tempo once a tempo has been set you can stop tapping and you'll coast at that tempo
if you tap again it resets the tempo latch, so if you just tapped once it's an easy way to pause if you tap again it resets the tempo latch, so if you just tapped once it's an easy way to pause
@ -74,6 +74,18 @@ todo
this makes it easier to play alongside a video, as your attention span can drift in and out this makes it easier to play alongside a video, as your attention span can drift in and out
and you can take tougher parts slower and you can take tougher parts slower
user prompt
for start and any other times we need to communicate simple instructions to the player
[!] snake can accidentally cover the menu
make depth easier to judge
pseudo light source is coming from your face (maybe at a diagonal *higher up* angler fish)
need some surface detail on the box faces (that fit within the art style)
benchmark
need to be able to play without moving/turning the box
bug(s) bug(s)
... ...

View file

@ -42,10 +42,12 @@ static class Arts
public static void Frame() public static void Frame()
{ {
// background bool vr = Device.DisplayBlend == DisplayBlend.Opaque;
if (Device.DisplayBlend == DisplayBlend.Opaque) // render hands if not in mixed reality
// Input.HandVisible(Handed.Max, vr);
if (vr)
{ {
// background standin if no passthrough
} }
// fullstick // fullstick
@ -65,7 +67,9 @@ static class Arts
); );
// box // box
Hierarchy.Push(Mono.box_pose.ToMatrix(Mono.box_scale)); // scale in
float box_scale = Mono.box_scale; // Maths.min(Maths.smooth_stop(Maths.u_scalar(Time.Totalf - 3)) * Mono.box_scale, Mono.box_scale);
Hierarchy.Push(Mono.box_pose.ToMatrix(box_scale));
// meshes["InsideOut"].Draw(mat_unlit, Matrix.Identity); // meshes["InsideOut"].Draw(mat_unlit, Matrix.Identity);
meshes["InsideOut"].Draw( meshes["InsideOut"].Draw(
mat_box, mat_box,
@ -116,7 +120,9 @@ static class Arts
); );
} }
string face = food_next ? "Face1Eat" : "Face0Default"; string face = "Face0Default";
face = Mono.grow_buffer > 0 ? "Face2Eaten" : face;
face = food_next ? "Face1Eat" : face;
meshes[face].Draw( meshes[face].Draw(
mat_mono, mat_mono,
Matrix.TRS( Matrix.TRS(
@ -143,7 +149,8 @@ static class Arts
); );
} }
// false tail // false tail
if (tailmove.state && snake_t < 1.0f) { if (tailmove.state && snake_t < 1.0f)
{
int i_tail = Maths.min(Mono.snake_len, Mono.snake.Length - 1); int i_tail = Maths.min(Mono.snake_len, Mono.snake.Length - 1);
Vec3 tail_dir = Vec3.Direction(Mono.snake[i_tail - 1].ToVec3, Mono.snake[i_tail].ToVec3); Vec3 tail_dir = Vec3.Direction(Mono.snake[i_tail - 1].ToVec3, Mono.snake[i_tail].ToVec3);
meshes["Segment"].Draw( meshes["Segment"].Draw(
@ -233,7 +240,7 @@ static class Arts
public static void Step() public static void Step()
{ {
XYZi snake_head = Mono.snake[0]; XYZi snake_head = Mono.snake[0];
XYZi snake_tail = Mono.snake[Mono.snake_len -1]; XYZi snake_tail = Mono.snake[Mono.snake_len - 1];
headmove.Step(snake_head != last_headpos); headmove.Step(snake_head != last_headpos);
tailmove.Step(snake_tail != last_tailpos); tailmove.Step(snake_tail != last_tailpos);
last_headpos = snake_head; last_headpos = snake_head;

View file

@ -5,17 +5,20 @@ namespace snake;
static class Mono static class Mono
{ {
public static double game_time = 0.0;
public static double step_step = 60.0 / 80; // 80|100|120 bpm public static double step_step = 60.0 / 80; // 80|100|120 bpm
public static double step_time = 0.0; public static double step_time = 0.0;
public static double step_t = 0.0; public static double step_t = 0.0;
public static double intro_skip = 0.0;
public static bool intro = true; // press to move until x condition or hold to skip
public static bool menu = true; public static bool menu = true;
public static Pose box_pose = new(0, -3 * U.cm, -10 * U.cm); public static Pose box_pose = new(0, -3 * U.cm, -10 * U.cm);
public static float box_scale = 1.333f * U.cm; public static float box_scale = 1.333f * U.cm;
public const int SD_X = 3, SD_Y = 2, SD_Z = 3; public const int SD_X = 3, SD_Y = 2, SD_Z = 3;
public static SpatialArray<int> public static SpatialArray<int>
box_space = new(SD_X-1, SD_Y-1, SD_Z-1, -1), box_space = new(SD_X - 1, SD_Y - 1, SD_Z - 1, -1),
s_array = new(SD_X, SD_Y, SD_Z, -1), s_array = new(SD_X, SD_Y, SD_Z, -1),
tail_fill = new(SD_X, SD_Y, SD_Z, -1); tail_fill = new(SD_X, SD_Y, SD_Z, -1);
@ -52,12 +55,21 @@ static class Mono
public static void Frame() public static void Frame()
{ {
if (Rig.btn_trigger.delta == +1) if (Rig.btn_back.delta == +1)
{ {
menu = !menu; menu = !menu;
SFX.click.PlayBox(new XYZi(0, 0, Mono.SD_Z + 1)); SFX.click.PlayBox(new XYZi(0, 0, Mono.SD_Z + 1));
} }
if (menu)
{
// just one btn(resume) in menu rn
if (Rig.btn_select.delta == +1)
{
menu = false;
}
}
// flatscreen dev controls // flatscreen dev controls
if (Device.Name == "Simulator") if (Device.Name == "Simulator")
{ {
@ -107,7 +119,7 @@ static class Mono
public static void Step() public static void Step()
{ {
// eat tail // eat tail
if (snake[0] + snake_dir == snake[snake_len-1]) if (snake[0] + snake_dir == snake[snake_len - 1])
{ {
snake_len--; snake_len--;
grow_buffer = 0; grow_buffer = 0;
@ -152,14 +164,11 @@ static class Mono
} }
// slither // slither
if (!menu)
{
for (int i = snake.Length - 1; i > 0; i--) for (int i = snake.Length - 1; i > 0; i--)
{ {
snake[i] = snake[i - 1]; snake[i] = snake[i - 1];
} }
snake[0] += snake_dir; snake[0] += snake_dir;
}
in_box.Step(box_space.InRange(snake[0])); in_box.Step(box_space.InRange(snake[0]));
if (in_box.delta != 0) // 1 just in -1 just out if (in_box.delta != 0) // 1 just in -1 just out
@ -189,7 +198,9 @@ static class Mono
SFX.crisp_nom.PlayBox(snake[0]); SFX.crisp_nom.PlayBox(snake[0]);
} }
} else { }
else
{
(bool viable, XYZi cell) = Feed(); (bool viable, XYZi cell) = Feed();
eaten_latch.Step(!viable); eaten_latch.Step(!viable);
if (eaten_latch.delta == -1) if (eaten_latch.delta == -1)
@ -209,9 +220,11 @@ static class Mono
// step from head using directions towards the tail // step from head using directions towards the tail
// and stop at either 1 cell away from the tail or 5 spaces away from the head // and stop at either 1 cell away from the tail or 5 spaces away from the head
bool viable = false; bool viable = false;
bool viable_step = false;
XYZi cell = snake[0]; XYZi cell = snake[0];
for (int step = 0; step < 5; step++) for (int step = 0; step < 5; step++)
{ {
viable_step = false;
int min_dist = 100; int min_dist = 100;
XYZi min_cell = new(); XYZi min_cell = new();
int[] dir_indices = GetShuffledIndices(directions); int[] dir_indices = GetShuffledIndices(directions);
@ -225,9 +238,14 @@ static class Mono
min_dist = tail_dist; min_dist = tail_dist;
min_cell = dir_cell; min_cell = dir_cell;
viable = true; viable = true;
viable_step = true;
} }
} }
if (viable_step)
{
tail_fill[min_cell] = -1; // prevent backtracking
cell = min_cell; cell = min_cell;
}
// if (min_dist <= 1) // if (min_dist <= 1)
// { // {
// break; // break;
@ -249,7 +267,7 @@ static class Mono
XYZi _sv = queue.Dequeue(); XYZi _sv = queue.Dequeue();
int currentDistance = fill_array[_sv]; int currentDistance = fill_array[_sv];
// check all 4 directions // check all 6 directions
foreach (XYZi dir in directions) foreach (XYZi dir in directions)
{ {
XYZi newV = _sv + dir; XYZi newV = _sv + dir;
@ -273,9 +291,7 @@ static class Mono
for (int i = indices.Length - 1; i > 0; i--) for (int i = indices.Length - 1; i > 0; i--)
{ {
int j = System.Random.Shared.Next(i + 1); int j = System.Random.Shared.Next(i + 1);
int temp = indices[i]; (indices[j], indices[i]) = (indices[i], indices[j]);
indices[i] = indices[j];
indices[j] = temp;
} }
return indices; return indices;
} }
@ -283,23 +299,23 @@ static class Mono
// directions for moving in the grid // directions for moving in the grid
static readonly XYZi[] directions = new XYZi[] static readonly XYZi[] directions = new XYZi[]
{ {
new XYZi(-1, 0, 0), // lft new(-1, 0, 0), // lft
new XYZi(+1, 0, 0), // rht new(+1, 0, 0), // rht
new XYZi(0, -1, 0), // dwn new(0, -1, 0), // dwn
new XYZi(0, +1, 0), // up new(0, +1, 0), // up
new XYZi(0, 0, -1), // fwd new(0, 0, -1), // fwd
new XYZi(0, 0, +1), // back new(0, 0, +1), // back
}; };
static readonly XYZi[] corners = new XYZi[] static readonly XYZi[] corners = new XYZi[]
{ {
new XYZi(-1, -1, -1), new(-1, -1, -1),
new XYZi(-1, -1, +1), new(-1, -1, +1),
new XYZi(-1, +1, -1), new(-1, +1, -1),
new XYZi(-1, +1, +1), new(-1, +1, +1),
new XYZi(+1, -1, -1), new(+1, -1, -1),
new XYZi(+1, -1, +1), new(+1, -1, +1),
new XYZi(+1, +1, -1), new(+1, +1, -1),
new XYZi(+1, +1, +1) new(+1, +1, +1)
}; };
static XYZi InsetCell(XYZi cell) static XYZi InsetCell(XYZi cell)

View file

@ -15,7 +15,7 @@ class Program
{ {
appName = "snake", appName = "snake",
assetsFolder = "Assets", assetsFolder = "Assets",
blendPreference = DisplayBlend.Blend, blendPreference = DisplayBlend.AnyTransparent,
// overlayApp = true, // overlayApp = true,
// overlayPriority = 1, // overlayPriority = 1,
depthMode = DepthMode.D32, depthMode = DepthMode.D32,
@ -29,12 +29,16 @@ class Program
Renderer.Scaling = 2; Renderer.Scaling = 2;
World.OcclusionEnabled = true; World.OcclusionEnabled = true;
// Device.DisplayBlend = DisplayBlend.Blend; Device.DisplayBlend = DisplayBlend.AnyTransparent;
Renderer.EnableSky = false;
Renderer.ClearColor = new Color(0.0f, 0.0f, 0.0f, 0.0f);
Rig.Init(); Rig.Init();
Mono.Init(); Mono.Init();
Arts.Init(); Arts.Init();
VCam.Init();
// Core application loop // Core application loop
SK.Run(() => SK.Run(() =>
{ {
@ -42,20 +46,62 @@ class Program
Mono.Frame(); Mono.Frame();
// stepper // stepper
if (Time.Total > 3.0) // if (Time.Total > 3.0) return; // buffer app loading [!] relace with user prompt to start (spawn box in hand or something)
if (!Mono.menu)
{ {
Mono.step_time += Time.Step; Mono.game_time += Time.Step;
Mono.step_t = Maths.min(Mono.step_time, Mono.step_step) / Mono.step_step; if (Mono.intro)
{
Mono.step_time = Maths.min(Mono.step_time + Time.Step, Mono.step_step);
Mono.step_t = Maths.u_clamp(Maths.min(Mono.step_time, Mono.step_step) / Mono.step_step);
if (Rig.btn_select.delta == +1)
{
Mono.step_time = 0.0;
Mono.step_t = 0.0;
Mono.Step();
Arts.Step();
if (Mono.grow_buffer > 0)
{
Mono.intro = false;
} }
if (Mono.step_time > Mono.step_step) }
if (Rig.btn_select.state)
{
Mono.intro_skip += Time.Step;
if (Mono.intro_skip >= 1.0)
{
Mono.intro = false;
}
}
if (Rig.btn_select.delta == -1)
{
Mono.intro_skip = 0.0;
}
}
else
{
Mono.step_time = Maths.min(Mono.step_time + Time.Step, Mono.step_step);
Mono.step_t = Maths.u_clamp(Maths.min(Mono.step_time, Mono.step_step) / Mono.step_step);
if (Mono.step_time >= Mono.step_step)
{ {
Mono.step_time -= Mono.step_step; Mono.step_time -= Mono.step_step;
Mono.step_t = 0.0;
Mono.Step(); Mono.Step();
Arts.Step(); Arts.Step();
} }
}
}
Arts.Frame(); Arts.Frame();
VCam.Frame();
}); });
} }
} }

View file

@ -6,8 +6,9 @@ static class Rig
{ {
public static Pose head = Pose.Identity; public static Pose head = Pose.Identity;
public static DeltaBool btn_trigger = new(false); public static DeltaBool btn_select = new(false);
public static DeltaBool btn_grip = new(false); public static DeltaBool btn_grip = new(false);
public static DeltaBool btn_back = new(false);
public static Vec3 fullstick = Vec3.Up; public static Vec3 fullstick = Vec3.Up;
public static Pose r_con_stick = Pose.Identity; public static Pose r_con_stick = Pose.Identity;
@ -26,7 +27,8 @@ static class Rig
// flatscreen dev controls // flatscreen dev controls
if (Device.Name == "Simulator") if (Device.Name == "Simulator")
{ {
btn_trigger.Step(Input.Key(Key.MouseLeft).IsActive()); btn_select.Step(Input.Key(Key.MouseLeft).IsActive());
btn_back.Step(Input.Key(Key.MouseRight).IsActive());
if (Input.Key(Key.A).IsJustActive()) new_dir = new(-1, 0, 0); if (Input.Key(Key.A).IsJustActive()) new_dir = new(-1, 0, 0);
if (Input.Key(Key.S).IsJustActive()) new_dir = new(+1, 0, 0); if (Input.Key(Key.S).IsJustActive()) new_dir = new(+1, 0, 0);
@ -44,11 +46,11 @@ static class Rig
bool con_tracked = r_con.trackedPos > TrackState.Lost; bool con_tracked = r_con.trackedPos > TrackState.Lost;
// bool hand_tracked = Input.HandSource(Handed.Right) > HandSource.None; // bool hand_tracked = Input.HandSource(Handed.Right) > HandSource.None;
Input.HandVisible(Handed.Max, false); // hide hands
if (con_tracked) if (con_tracked)
{ {
btn_trigger.Step(r_con.trigger > 0.5f); btn_select.Step(r_con.x1.IsActive() || r_con.trigger > 0.5f);
btn_grip.Step(r_con.grip > 0.5f); btn_grip.Step(r_con.grip > 0.5f);
btn_back.Step(r_con.x2.IsActive());
Vec2 stick = r_con.stick; Vec2 stick = r_con.stick;
Quat stick_rot = Quat.FromAngles(stick.y * -90, 0, stick.x * +90); Quat stick_rot = Quat.FromAngles(stick.y * -90, 0, stick.x * +90);

42
src/VCam.cs Normal file
View file

@ -0,0 +1,42 @@
using StereoKit;
namespace snake;
static class VCam
{
// [!] clear directory before recording
// or better yet just overwrite and then delete anything that wasn't overwritten at the end
// [!] write documentation for making a video
// for example a kdenlive project file that is preconfigured for 60fps VP9 transparent webm etc
public static float t = 0.0f; // use this to stage loops *start by rotating 360 degrees
public static int frame_index = 0;
public static bool recording = false;
public static Pose pose = new(0, 0, 0);
public static void Init()
{
}
public static void Frame()
{
if (Input.Key(Key.N).IsJustActive())
{
recording = !recording;
}
pose.position = Input.Head.position;
pose.orientation = Input.Head.orientation;
if (recording)
{
frame_index++;
Renderer.Screenshot(
$"_frames/test_{frame_index:D4}.png",
pose,
1280,
720
);
}
}
}