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/
Raw/
_frames/
.vscode
anchors.txt

View file

@ -2,8 +2,8 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.dofdev.snake"
android:versionCode="17"
android:versionName="1.27"
android:versionCode="29"
android:versionName="1.32"
android:installLocation="auto"
>
<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
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
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
@ -74,6 +74,18 @@ todo
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
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)
...

View file

@ -42,10 +42,12 @@ static class Arts
public static void Frame()
{
// background
if (Device.DisplayBlend == DisplayBlend.Opaque)
bool vr = Device.DisplayBlend == DisplayBlend.Opaque;
// render hands if not in mixed reality
// Input.HandVisible(Handed.Max, vr);
if (vr)
{
// background standin if no passthrough
}
// fullstick
@ -65,7 +67,9 @@ static class Arts
);
// 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_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(
mat_mono,
Matrix.TRS(
@ -143,7 +149,8 @@ static class Arts
);
}
// 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);
Vec3 tail_dir = Vec3.Direction(Mono.snake[i_tail - 1].ToVec3, Mono.snake[i_tail].ToVec3);
meshes["Segment"].Draw(
@ -233,7 +240,7 @@ static class Arts
public static void Step()
{
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);
tailmove.Step(snake_tail != last_tailpos);
last_headpos = snake_head;

View file

@ -5,17 +5,20 @@ namespace snake;
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_time = 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 Pose box_pose = new(0, -3 * U.cm, -10 * U.cm);
public static float box_scale = 1.333f * U.cm;
public const int SD_X = 3, SD_Y = 2, SD_Z = 3;
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),
tail_fill = new(SD_X, SD_Y, SD_Z, -1);
@ -52,12 +55,21 @@ static class Mono
public static void Frame()
{
if (Rig.btn_trigger.delta == +1)
if (Rig.btn_back.delta == +1)
{
menu = !menu;
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
if (Device.Name == "Simulator")
{
@ -107,7 +119,7 @@ static class Mono
public static void Step()
{
// eat tail
if (snake[0] + snake_dir == snake[snake_len-1])
if (snake[0] + snake_dir == snake[snake_len - 1])
{
snake_len--;
grow_buffer = 0;
@ -152,14 +164,11 @@ static class Mono
}
// 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[0] += snake_dir;
snake[i] = snake[i - 1];
}
snake[0] += snake_dir;
in_box.Step(box_space.InRange(snake[0]));
if (in_box.delta != 0) // 1 just in -1 just out
@ -189,7 +198,9 @@ static class Mono
SFX.crisp_nom.PlayBox(snake[0]);
}
} else {
}
else
{
(bool viable, XYZi cell) = Feed();
eaten_latch.Step(!viable);
if (eaten_latch.delta == -1)
@ -209,9 +220,11 @@ static class Mono
// 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
bool viable = false;
bool viable_step = false;
XYZi cell = snake[0];
for (int step = 0; step < 5; step++)
{
viable_step = false;
int min_dist = 100;
XYZi min_cell = new();
int[] dir_indices = GetShuffledIndices(directions);
@ -225,9 +238,14 @@ static class Mono
min_dist = tail_dist;
min_cell = dir_cell;
viable = true;
viable_step = true;
}
}
cell = min_cell;
if (viable_step)
{
tail_fill[min_cell] = -1; // prevent backtracking
cell = min_cell;
}
// if (min_dist <= 1)
// {
// break;
@ -249,7 +267,7 @@ static class Mono
XYZi _sv = queue.Dequeue();
int currentDistance = fill_array[_sv];
// check all 4 directions
// check all 6 directions
foreach (XYZi dir in directions)
{
XYZi newV = _sv + dir;
@ -273,9 +291,7 @@ static class Mono
for (int i = indices.Length - 1; i > 0; i--)
{
int j = System.Random.Shared.Next(i + 1);
int temp = indices[i];
indices[i] = indices[j];
indices[j] = temp;
(indices[j], indices[i]) = (indices[i], indices[j]);
}
return indices;
}
@ -283,23 +299,23 @@ static class Mono
// directions for moving in the grid
static readonly XYZi[] directions = new XYZi[]
{
new XYZi(-1, 0, 0), // lft
new XYZi(+1, 0, 0), // rht
new XYZi(0, -1, 0), // dwn
new XYZi(0, +1, 0), // up
new XYZi(0, 0, -1), // fwd
new XYZi(0, 0, +1), // back
new(-1, 0, 0), // lft
new(+1, 0, 0), // rht
new(0, -1, 0), // dwn
new(0, +1, 0), // up
new(0, 0, -1), // fwd
new(0, 0, +1), // back
};
static readonly XYZi[] corners = new XYZi[]
{
new XYZi(-1, -1, -1),
new XYZi(-1, -1, +1),
new XYZi(-1, +1, -1),
new XYZi(-1, +1, +1),
new XYZi(+1, -1, -1),
new XYZi(+1, -1, +1),
new XYZi(+1, +1, -1),
new XYZi(+1, +1, +1)
new(-1, -1, -1),
new(-1, -1, +1),
new(-1, +1, -1),
new(-1, +1, +1),
new(+1, -1, -1),
new(+1, -1, +1),
new(+1, +1, -1),
new(+1, +1, +1)
};
static XYZi InsetCell(XYZi cell)

View file

@ -15,7 +15,7 @@ class Program
{
appName = "snake",
assetsFolder = "Assets",
blendPreference = DisplayBlend.Blend,
blendPreference = DisplayBlend.AnyTransparent,
// overlayApp = true,
// overlayPriority = 1,
depthMode = DepthMode.D32,
@ -29,12 +29,16 @@ class Program
Renderer.Scaling = 2;
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();
Mono.Init();
Arts.Init();
VCam.Init();
// Core application loop
SK.Run(() =>
{
@ -42,20 +46,62 @@ class Program
Mono.Frame();
// stepper
if (Time.Total > 3.0)
{
Mono.step_time += Time.Step;
Mono.step_t = Maths.min(Mono.step_time, Mono.step_step) / Mono.step_step;
}
if (Mono.step_time > Mono.step_step)
{
Mono.step_time -= Mono.step_step;
// if (Time.Total > 3.0) return; // buffer app loading [!] relace with user prompt to start (spawn box in hand or something)
Mono.Step();
Arts.Step();
if (!Mono.menu)
{
Mono.game_time += Time.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 (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_t = 0.0;
Mono.Step();
Arts.Step();
}
}
}
Arts.Frame();
VCam.Frame();
});
}
}

View file

@ -6,8 +6,9 @@ static class Rig
{
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_back = new(false);
public static Vec3 fullstick = Vec3.Up;
public static Pose r_con_stick = Pose.Identity;
@ -26,7 +27,8 @@ static class Rig
// flatscreen dev controls
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.S).IsJustActive()) new_dir = new(+1, 0, 0);
@ -44,11 +46,11 @@ static class Rig
bool con_tracked = r_con.trackedPos > TrackState.Lost;
// bool hand_tracked = Input.HandSource(Handed.Right) > HandSource.None;
Input.HandVisible(Handed.Max, false); // hide hands
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_back.Step(r_con.x2.IsActive());
Vec2 stick = r_con.stick;
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
);
}
}
}