snake -> slash

This commit is contained in:
ethan merchant 2024-11-29 13:06:28 -05:00
parent 218d5b40f7
commit dd6206c5a0
14 changed files with 142 additions and 142 deletions

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.dofdev.snake"
package="com.dofdev.slash"
android:versionCode="48"
android:versionName="1.53"
android:installLocation="auto"
@ -54,7 +54,7 @@
<application
android:allowBackup="false"
android:icon="@mipmap/appicon"
android:label="Snake in a Box"
android:label="slash in a Box"
android:roundIcon="@mipmap/appicon_round"
android:supportsRtl="true"
>
@ -71,7 +71,7 @@
<meta-data android:name="spaces.version" android:value="0.15.0" />
<activity
android:name="snake.MainActivity"
android:name="slash.MainActivity"
android:launchMode="singleTask"
android:excludeFromRecents="false"
android:screenOrientation="landscape"

View file

@ -9,79 +9,79 @@ using System;
using System.Reflection;
using System.Threading;
namespace snake;
namespace slash;
[Activity(Label = "@string/app_name", MainLauncher = true, Exported = true)]
[IntentFilter(new[] { Intent.ActionMain }, Categories = new[] { "org.khronos.openxr.intent.category.IMMERSIVE_HMD", "com.oculus.intent.category.VR", Intent.CategoryLauncher })]
public class MainActivity : Activity, ISurfaceHolderCallback2
{
View surface;
View surface;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Run();
SetContentView(Resource.Layout.activity_main);
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Run();
SetContentView(Resource.Layout.activity_main);
}
protected override void OnDestroy()
{
SK.Quit();
base.OnDestroy();
}
protected override void OnDestroy()
{
SK.Quit();
base.OnDestroy();
}
static bool running = false;
void Run()
{
if (running) return;
running = true;
static bool running = false;
void Run()
{
if (running) return;
running = true;
// Before anything else, give StereoKit the Activity. This should
// be set before any other SK calls, otherwise native library
// loading may fail.
SK.AndroidActivity = this;
// Before anything else, give StereoKit the Activity. This should
// be set before any other SK calls, otherwise native library
// loading may fail.
SK.AndroidActivity = this;
// Set up a surface for StereoKit to draw on, this is only really
// important for flatscreen experiences.
Window.TakeSurface(this);
Window.SetFormat(Format.Unknown);
surface = new View(this);
SetContentView(surface);
surface.RequestFocus();
// Set up a surface for StereoKit to draw on, this is only really
// important for flatscreen experiences.
Window.TakeSurface(this);
Window.SetFormat(Format.Unknown);
surface = new View(this);
SetContentView(surface);
surface.RequestFocus();
// Task.Run will eat exceptions, but Thread.Start doesn't seem to.
new Thread(InvokeStereoKit).Start();
}
// Task.Run will eat exceptions, but Thread.Start doesn't seem to.
new Thread(InvokeStereoKit).Start();
}
static void InvokeStereoKit()
{
Type entryClass = typeof(Program);
MethodInfo entryPoint = entryClass?.GetMethod("Main", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
static void InvokeStereoKit()
{
Type entryClass = typeof(Program);
MethodInfo entryPoint = entryClass?.GetMethod("Main", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
// There are a number of potential method signatures for Main, so
// we need to check each one, and give it the correct values.
//
// Converting MethodInfo into an Action instead of calling Invoke on
// it allows for exceptions to properly bubble up to the IDE.
ParameterInfo[] entryParams = entryPoint?.GetParameters();
if (entryParams == null || entryParams.Length == 0)
{
Action Program_Main = (Action)Delegate.CreateDelegate(typeof(Action), entryPoint);
Program_Main();
}
else if (entryParams?.Length == 1 && entryParams[0].ParameterType == typeof(string[]))
{
Action<string[]> Program_Main = (Action<string[]>)Delegate.CreateDelegate(typeof(Action<string[]>), entryPoint);
Program_Main(new string[] { });
}
else throw new Exception("Couldn't invoke Program.Main!");
// There are a number of potential method signatures for Main, so
// we need to check each one, and give it the correct values.
//
// Converting MethodInfo into an Action instead of calling Invoke on
// it allows for exceptions to properly bubble up to the IDE.
ParameterInfo[] entryParams = entryPoint?.GetParameters();
if (entryParams == null || entryParams.Length == 0)
{
Action Program_Main = (Action)Delegate.CreateDelegate(typeof(Action), entryPoint);
Program_Main();
}
else if (entryParams?.Length == 1 && entryParams[0].ParameterType == typeof(string[]))
{
Action<string[]> Program_Main = (Action<string[]>)Delegate.CreateDelegate(typeof(Action<string[]>), entryPoint);
Program_Main(new string[] { });
}
else throw new Exception("Couldn't invoke Program.Main!");
Process.KillProcess(Process.MyPid());
}
Process.KillProcess(Process.MyPid());
}
// Events related to surface state changes
public void SurfaceChanged (ISurfaceHolder holder, [GeneratedEnum] Format format, int width, int height) => SK.SetWindow(holder.Surface.Handle);
public void SurfaceCreated (ISurfaceHolder holder) => SK.SetWindow(holder.Surface.Handle);
public void SurfaceDestroyed (ISurfaceHolder holder) => SK.SetWindow(IntPtr.Zero);
public void SurfaceRedrawNeeded(ISurfaceHolder holder) { }
// Events related to surface state changes
public void SurfaceChanged(ISurfaceHolder holder, [GeneratedEnum] Format format, int width, int height) => SK.SetWindow(holder.Surface.Handle);
public void SurfaceCreated(ISurfaceHolder holder) => SK.SetWindow(holder.Surface.Handle);
public void SurfaceDestroyed(ISurfaceHolder holder) => SK.SetWindow(IntPtr.Zero);
public void SurfaceRedrawNeeded(ISurfaceHolder holder) { }
}

View file

@ -1,4 +1,4 @@
<resources>
<string name="app_name">snake</string>
<string name="app_text">snake</string>
<string name="app_name">slash</string>
<string name="app_text">slash</string>
</resources>

View file

@ -4,10 +4,10 @@
<RuntimeIdentifiers>android-arm64</RuntimeIdentifiers>
<SupportedOSPlatformVersion>29</SupportedOSPlatformVersion>
<OutputType>Exe</OutputType>
<ApplicationId>com.dofdev.snake</ApplicationId>
<ApplicationId>com.dofdev.slash</ApplicationId>
<ApplicationVersion>1</ApplicationVersion>
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<RootNamespace>snake</RootNamespace>
<RootNamespace>slash</RootNamespace>
<ReadOnlyProject>true</ReadOnlyProject>
<SKOpenXRLoader>Standard</SKOpenXRLoader>

View file

@ -24,16 +24,16 @@ adb connect 192.168.1.219
# publish build
# increment version in Platforms/Android/AndroidManifest.xml
dotnet publish -c Release Projects/Android/snake.Android.csproj
dotnet publish -c Release Projects/Android/slash.Android.csproj
# adb install Projects/Android/bin/Release/net7.0-android/com.dofdev.snake-Signed.apk
# adb install Projects/Android/bin/Release/net7.0-android/com.dofdev.slash-Signed.apk
# upload quest
source .env
./ovr-platform-util upload-quest-build -a $APP_ID -s $APP_SECRET --apk $APK_PATH -c alpha -n "message"
# debug
adb logcat | grep com.dofdev.snake
adb logcat | grep com.dofdev.slash
# install a specific android platform
@ -53,8 +53,8 @@ todo
seated experience on the Meta Quest 3/3S
moderate learning curve
start outside of the box (about 6-9 segments long)
snake is moving like normal but is parented to an offset pose that keeps their head centered
so you can easily get a feel for how the snake moves
slash is moving like normal but is parented to an offset pose that keeps their head centered
so you can easily get a feel for how the slash moves
(sort of like writhing around in zero g)
*dreamlike*
wake up in box
@ -86,6 +86,6 @@ todo
and you can take tougher parts slower
bug(s)
snake can accidentally cover the menu
slash can accidentally cover the menu
```

View file

@ -1,7 +1,7 @@
using System.Collections.Generic;
using StereoKit;
namespace snake;
namespace slash;
static class Arts
{
@ -149,14 +149,14 @@ static class Arts
);
}
// snake
float snake_t = headmove.state ? Maths.u_clamp(Maths.smooth_stop((float)Mono.step_t) * 3.0f) : 1.0f;
// slash
float slash_t = headmove.state ? Maths.u_clamp(Maths.smooth_stop((float)Mono.step_t) * 3.0f) : 1.0f;
if (!Mono.menu && !Mono.food_next.state)
{
meshes["Tongue"].Draw(
mat_mono,
Matrix.TRS(
Mono.snake[0].ToVec3,
Mono.slash[0].ToVec3,
Quat.LookDir(Rig.fullstick),
V.XYZ(1, 1, 0.666f + Maths.smooth_stop((float)Mono.step_t) * 0.333f)
)
@ -170,39 +170,39 @@ static class Arts
meshes[face].Draw(
mat_mono,
Matrix.TRS(
Mono.snake[0].ToVec3 - (Mono.snake_dir.ToVec3 * (float)(1.0 - snake_t) * 0.3f),
Quat.LookDir(Mono.snake_dir.ToVec3),
V.XYZ(1, 1, (float)(snake_t))
Mono.slash[0].ToVec3 - (Mono.slash_dir.ToVec3 * (float)(1.0 - slash_t) * 0.3f),
Quat.LookDir(Mono.slash_dir.ToVec3),
V.XYZ(1, 1, (float)(slash_t))
)
);
for (int i = 1; i < Mono.snake_len; i++)
for (int i = 1; i < Mono.slash_len; i++)
{
float scale = 1.0f;
if ((int)((Time.Total - Mono.eat_timestamp) * Mono.snake_len / Mono.step_step) == i)
if ((int)((Time.Total - Mono.eat_timestamp) * Mono.slash_len / Mono.step_step) == i)
{
scale = 1.1f;
}
meshes["Segment"].Draw(
mat_mono,
Matrix.TRS(
Mono.snake[i].ToVec3,
Quat.LookAt(Mono.snake[i].ToVec3, Mono.snake[i - 1].ToVec3),
Mono.slash[i].ToVec3,
Quat.LookAt(Mono.slash[i].ToVec3, Mono.slash[i - 1].ToVec3),
scale
)
);
}
// false tail
if (tailmove.state && snake_t < 1.0f)
if (tailmove.state && slash_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);
int i_tail = Maths.min(Mono.slash_len, Mono.slash.Length - 1);
Vec3 tail_dir = Vec3.Direction(Mono.slash[i_tail - 1].ToVec3, Mono.slash[i_tail].ToVec3);
meshes["Segment"].Draw(
mat_mono,
Matrix.TRS(
Mono.snake[i_tail].ToVec3 + (tail_dir * (float)(snake_t) * 0.7f),
Mono.slash[i_tail].ToVec3 + (tail_dir * (float)(slash_t) * 0.7f),
Quat.LookDir(tail_dir),
V.XYZ(1, 1, (float)(1.0 - snake_t))
V.XYZ(1, 1, (float)(1.0 - slash_t))
)
);
}
@ -249,13 +249,13 @@ static class Arts
if (Mono.eaten == 0)
{
// starting egg
bool in_snake = Mono.s_array[new XYZi(0, 0, 0)] > -1;
bool in_slash = Mono.s_array[new XYZi(0, 0, 0)] > -1;
meshes["Egg"].Draw(
mat_mono,
Matrix.TRS(
Vec3.Zero,
in_snake ? Quat.Identity : food_ori,
in_snake ? 1 : 0.5f
in_slash ? Quat.Identity : food_ori,
in_slash ? 1 : 0.5f
)
);
}
@ -292,7 +292,7 @@ static class Arts
}
// score
char[] score_txt = Mono.snake_len.ToString("000").ToCharArray();
char[] score_txt = Mono.slash_len.ToString("000").ToCharArray();
Quat score_ori = Quat.LookDir(Rig.head.position - Mono.box_pose.position);
Vec3 score_pos = score_ori * V.XYZ(0, -Mono.SD_Y - 1.5f, -Mono.SD_Z - 1);
for (int i = 0; i < score_txt.Length; i++)
@ -332,11 +332,11 @@ static class Arts
public static void Step()
{
XYZi snake_head = Mono.snake[0];
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;
last_tailpos = snake_tail;
XYZi slash_head = Mono.slash[0];
XYZi slash_tail = Mono.slash[Mono.slash_len - 1];
headmove.Step(slash_head != last_headpos);
tailmove.Step(slash_tail != last_tailpos);
last_headpos = slash_head;
last_tailpos = slash_tail;
}
}

View file

@ -1,6 +1,6 @@
using System;
namespace snake;
namespace slash;
public static class Maths
{

View file

@ -1,7 +1,7 @@
using System.Collections.Generic;
using StereoKit;
namespace snake;
namespace slash;
static class Mono
{
@ -26,18 +26,18 @@ static class Mono
static void update_s_array()
{
s_array.Clear(-1);
for (int i = 0; i < snake_len; i++)
for (int i = 0; i < slash_len; i++)
{
s_array[snake[i]] = i;
s_array[slash[i]] = i;
}
}
public static XYZi[] snake = new XYZi[
public static XYZi[] slash = new XYZi[
Maths.u_length(SD_X) * Maths.u_length(SD_Y) * Maths.u_length(SD_Z)
];
public static int snake_len = 1;
public static int slash_len = 1;
public static int grow_buffer = 3;
public static XYZi snake_dir = new(0, 0, 1);
public static XYZi slash_dir = new(0, 0, 1);
public static DeltaBool in_box = new(true);
public static Dictionary<XYZi, XYZi> holes = new();
public static XYZi food = new(0, 0, 0); // [!] start random to keep new game fresh?
@ -59,9 +59,9 @@ static class Mono
public static void Init()
{
for (int i = 0; i < snake.Length; i++)
for (int i = 0; i < slash.Length; i++)
{
snake[i] = new XYZi(0, 0, 0);
slash[i] = new XYZi(0, 0, 0);
}
update_s_array();
}
@ -124,35 +124,35 @@ static class Mono
}
}
XYZi next_pos = snake[0] + Rig.new_dir;
bool neck_break = next_pos == snake[1];
XYZi next_pos = slash[0] + Rig.new_dir;
bool neck_break = next_pos == slash[1];
if (!neck_break && !food_next.state)
{
snake_dir = Rig.new_dir;
slash_dir = Rig.new_dir;
}
food_next.Step(!Mono.eaten_latch.state && (Mono.snake[0] + Mono.snake_dir) == Mono.food);
food_next.Step(!Mono.eaten_latch.state && (Mono.slash[0] + Mono.slash_dir) == Mono.food);
if (food_next.delta == +1)
{
SFX.maw.PlayBox(Mono.snake[0]);
SFX.maw.PlayBox(Mono.slash[0]);
}
}
public static void Step()
{
// eat tail
if (snake[0] + snake_dir == snake[snake_len - 1])
if (slash[0] + slash_dir == slash[slash_len - 1])
{
snake_len--;
slash_len--;
grow_buffer = 0;
}
else if (s_array[snake[0] + snake_dir] > -1)
else if (s_array[slash[0] + slash_dir] > -1)
{
// lose condition
bool stuck = true;
for (int i = 0; i < directions.Length; i++)
{
if (s_array[snake[0] + directions[i]] == -1)
if (s_array[slash[0] + directions[i]] == -1)
{
stuck = false;
}
@ -164,7 +164,7 @@ static class Mono
return;
}
bool in_or_around_box = s_array.InRange(snake[0] + snake_dir);
bool in_or_around_box = s_array.InRange(slash[0] + slash_dir);
if (!in_or_around_box)
{
return;
@ -172,39 +172,39 @@ static class Mono
if (eaten_latch.delta != +1)
{
if (snake_len == snake.Length)
if (slash_len == slash.Length)
{
// win condition
Log.Info("full snake");
Log.Info("full slash");
return;
}
else
{
if (grow_buffer > 0)
{
snake_len++;
slash_len++;
grow_buffer--;
}
}
// slither
for (int i = snake.Length - 1; i > 0; i--)
for (int i = slash.Length - 1; i > 0; i--)
{
snake[i] = snake[i - 1];
slash[i] = slash[i - 1];
}
snake[0] += snake_dir;
slash[0] += slash_dir;
}
in_box.Step(box_space.InRange(snake[0]));
in_box.Step(box_space.InRange(slash[0]));
if (in_box.delta != 0) // 1 just in -1 just out
{
holes.Add(snake[0], snake_dir);
SFX.punch_through.PlayBox(snake[0]);
Arts.box_shake += snake_dir.ToVec3;
holes.Add(slash[0], slash_dir);
SFX.punch_through.PlayBox(slash[0]);
Arts.box_shake += slash_dir.ToVec3;
}
if (holes.ContainsKey(snake[snake_len - 1]))
if (holes.ContainsKey(slash[slash_len - 1]))
{
holes.Remove(snake[snake_len - 1]);
holes.Remove(slash[slash_len - 1]);
}
update_s_array();
@ -212,15 +212,15 @@ static class Mono
// eat
if (!eaten_latch.state)
{
eaten_latch.Step(food == snake[0]);
eaten_latch.Step(food == slash[0]);
if (eaten_latch.delta == +1)
{
eat_timestamp = Time.Total;
grow_buffer += 3;
eaten++;
VFX.Play(snake[0]);
SFX.crisp_nom.PlayBox(snake[0]);
VFX.Play(slash[0]);
SFX.crisp_nom.PlayBox(slash[0]);
}
}
else
@ -239,13 +239,13 @@ static class Mono
// [!] handle out of the box exception on tail
// by making the spatial arrays encapsulate the layer outside of the box
tail_fill.Clear(-1);
Gas(tail_fill, snake[snake_len - 1]);
Gas(tail_fill, slash[slash_len - 1]);
// 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];
XYZi cell = slash[0];
for (int step = 0; step < 5; step++)
{
viable_step = false;

View file

@ -2,7 +2,7 @@ using StereoKit;
using StereoKit.Framework;
namespace snake;
namespace slash;
class Program
{
@ -13,7 +13,7 @@ class Program
// Initialize StereoKit
SKSettings settings = new SKSettings
{
appName = "snake",
appName = "slash",
assetsFolder = "Assets",
blendPreference = DisplayBlend.AnyTransparent,
// overlayApp = true,

View file

@ -1,6 +1,6 @@
using StereoKit;
namespace snake;
namespace slash;
static class Rig
{

View file

@ -1,6 +1,6 @@
using StereoKit;
namespace snake;
namespace slash;
static class SFX
{

View file

@ -1,6 +1,6 @@
using StereoKit;
namespace snake;
namespace slash;
static class VCam
{

View file

@ -1,7 +1,7 @@
using StereoKit;
using System;
namespace snake;
namespace slash;
static class VFX
{