Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics

Sophie Houlden

A member registered Mar 27, 2013 · View creator page →

Creator of

Recent community posts

I think it is fine, so long as those websites or other elements don’t have content that goes against the rules (is bigoted, hurtful, hateful, or unkind) or could expose players to any kind of danger.

It’s definitely an interesting idea worth exploring, where gamebooks meet ARGs perhaps?

To be clear: any kind of gameplay (or things that aren’t gameplay) is welcome, you don’t need to follow any gamebook conventions at all, just be considerate of your players/readers/audience :)

It is 100% alright 👍

I like putting most of my stuff on sale at the same time, but I don't necessarily want the same discount applied to all of it.

Right now I have a 75% off sale for my older projects, and a 35% off sale for my newer projects.

It's a little awkward and obviously all the games can't be bought togetherat once this way. Being able to set different rates for projects in a sale would mean I could include everything in a single bundle without worrying about devaluing my more recently released work.

The rules are simple;

  • Make whatever you want, it doesn't even have to be a gamebook
  • You can start early if you want
  • You can work on existing/unfinished projects
  • You can work solo or with others
  • If you want the submission deadline extended, just ask
  • Don't be a jerk - bigotted, phobic, hurtful, hateful, and unkind stuff is all unwelcome.

If you have any Qs, ask below :)

(1 edit)

hey, sorry I haven’t explained this clearly! I’m going to try and record a tutorial video later but for now here’s the best explanation I can give:

User values are applied to any roll expressions made (that is rolls made by typing out dice notation), they have nothing to do with dice bags. so you will need to make separate sets for your barbarian and your bard, making sure to disable the ones you are not using.

roll expressions can  be saved into dice bags however; when picking which dice to roll, they look in the current dice bag first. so with barbarian user values enabled and the barbarian dice bag open, entering a roll expression d20+str should use your barbarian’s d20 and their “str” value.

I hope that helps, let me know if you still have any issues :)

Update: I recorded that tutorial :)

I am honestly not sure if they will run tbh, but I have reenabled the 1.0 and 1.1 releases so you can try them. I don’t think either is too likely though since they weren’t released that much earlier and have similar build settings.

being able to save presets is a good idea, it’s not possible right now but I’ll add it to my to-do list :)

Hey, it is a thing you can do, I just haven’t gotten around to documenting it properly yet. The way to do it is locate the Session Data folder (it should be at: Documents/SophiesCubes/SessionData)

put your images in there, and the next time you open the app, the images will be loaded and can be applied when creating a cube in a new session.

If you have any problems with that just let me know, I’ll do what I can to help :)

There isn't any way to do that right now, sorry! But It's a really good idea to be able to do that, so I'm adding it to my list of features to try implementing the next time I'm working on the app :)

hi Jordan! Sorry I might not be much help right now as it’s been a while since I dug deep into the code but IIRC, Sinput.mouseSensitivity is a separate setting to what users can adjust in the rebind scene (I might be wrong though, but it should be easy enough for you to test with what you are doing now?)

I do know that you can (and in a few cases *should*) separate mouse and gamepad inputs for things like looking around, Sinput has a PrefersDeltaUse() function for this (check the “Framerate Independent Inputs” part of the documentation here) - generally, if this returns false then the input is from a mouse (on the frame you’re checking, if they switch to a gamepad stick it will become true), and you can multiply the input by your own scaling factor within a conditional.

I hope this is some help! If not let me know and I can try digging through the code for a refresher so I can give a better answer :)

Hey thanks for letting me know about this!

I’m not sure what I intended for the behaviour here to be but this is definitely not consistent, sorry about that!

It will probably be a while before I do anything about this issue, but for now if you want to keep all pinned dice when using a saved roll; throw out another die first, it will remove only that one when you select your saved roll.

the results will total all dice pools so you will get the sum value if you try to roll it all at once.

BUT if you enable the “show pool values” option, each dice pool’s value will be displayed below the results, you can then roll:

“4d6R{1}L + 4d6R{1}L + 4d6R{1}L + 4d6R{1}L + 4d6R{1}L + 4d6R{1}L”

And see the different values (ignoring the main result)

Definitely an influence :)

Technically not 'sleepy' but the original idea is: you get a prompt before bed and try to overcome some problem in the daydream world before you fall asleep. Whatever you remember in the morining is your result :)

As an update, the 1.1 version went live today and the CustomDice directory can be somewhere else now. I haven't updated the documentation for it just yet but after you run the new version of the app., there will be a file called "settings.set" saved in the app data folder (a folder beside or inside the app).

inside the settings.set will be a list of properties, change "CustomDiceDirectory" to be the location you want for your custom dice folder. You can also set it to "*" (without the quotation marks) to save dice in a directory relative to the app, should you want to carry the program around on an externam drive :)

Not right now sorry, but it's a feature on my priority to-do list so it should be possible in the next version :)

That actually looks pretty solid, I'll probably do something similar in a future version. Thanks for the heads-up :)

I don't have any plans to run another Tomb Raider jam, but if you want me to extend the deadline again I can keep it going for longer :)

You can absolutely do that! Make the game you want to make! :)

I've extended the jam an extra month, right now it will end mid-January, so you don't have to worry about hustling if you'd rather be enjoying holidays/new years :)

For WebGL: I have no idea how gamepad support works with unity webgl builds! According to the docs it seems it's the same as standalone builds so I think Sinput should work, but if not let me know and I'll try and figure it out :)

Wow I totally missed this thread, sorry!

For console: it will work. You'll need to set up common mappings for the console's gamepads but that should be straightforward.

However you should keep in mind that Sinput only wraps the Unity Input systems, it doesn't add any new functionality so if you want rumble/motion control/touchpad input/etc, Sinput isn't going to be able to manage. For that I'd hope the console you're developing for provides their own libraries? tbh I'm not sure about the specifics, the only console I've actually published a game on was OUYA :P

If you need any help I'll do what I can (just get in touch via twitter or email if it's urgent, apparently I miss forum posts for a long time :P) but I may have limits to how much I can help as I'm not a registered developer for most consoles.

(1 edit)

I've not made a repository before and tbh I'm a little hesitant about it all, but I've tried to set one up here anyway:

It currently has some changes/additions that are going to be in the Sinput_F version, mostly XR stuff.

Plz let me know if I'm doing something super wrong or whatever, and if you figure out what is generating the junk I'd appreciate it. I have done a few passes to minimise that but it's been a while and there's always gonna be stuff I don't know about optimisation ^_^;

edit: oh and I just pushed a change to fix the getslotpress bug, thx!

I love these!

(1 edit)

The Important Rule:

The only real rule is: "Don't be hurtful or harmful", breaking this rule will get you banned.

Now for the FAQ:

What should/can I make for this jam?

Anything you want. All types of work will be accepted; games, comics, poems, cosplay, recipes, whatever you're inspired to make is fine.

Will there be a winner/scoring/prizes?

No to all of that. This is a relaxed non-competitive jam. Unless you want to compete with a friend or whatever, but you'll have to arrange that between yourselves :)

When is the jam?

Submissions are open from 15th October until 15th December, but if you need me to extend the deadline I probably will. The jam can be extended for as long as needed really, so long as moderating it doesn't become too much work for me :)

Can I start work early?

Yes! If you want to get started before the jam starts accepting submissions then that is super cool!

Do I have to work solo or can we work as a team?

You can work however you want! If you're looking for people to work with then check out the 'Team-up!' community category, or ask around on Twitter using #TombRaiderJam.

Where can I post my progress?

You can share your progress during the jam here. (or anywhere else on the internet, but I can't really make sure people commenting elsewhere are following the important rule, sorry)

Can I use Tomb Raider IP?

Legally? Probably not. This is a game jam organised by and for fans of Tomb Raider. We're basically making fan-art here. If you're going to be selling or accepting tips for whatever you make I'd recommend thinking twice before using any Tomb Raider intellectual property.

If you have any other questions, ask below. Good luck with the jam, I hope you have fun!

Sorry for the slow reply!

Your Dualshock 4 ~should~ work, but if your pad identifies as something different to mine, it will default to xbox mapping. And if your driver maps differently, it will have incorrect mapping by default.

If you check the GamepadTesting scene (in the Utilities folder) and see what name the gamepad is listed as, you can check the PS4_osx common mapping and see if the name is listed. If not, add it to the list of gamepad names and assuming the mapping is the same, it will work.

If the name is different or you need to make different mapping for it, please let me know (and maybe send me your common mapping asset) and I can include it in future versions :)

hope this helps!

Most of the terms for smart controls are equivalent to input axis settings, for clarification:

  • Deadzone - values of smaller magnitude aren't returned
  • Gravity - how quickly the value moves to 0
  • Speed - how quickly the value moves towards it's raw input value
  • Snap - if the raw input value is positive and the current value is negative, snaps to zero (and vice-versa)
  • Scale - any returned value gets multiplied by this
  • Invert - if true returned values are multiplied by -1

Sounds like you figured it out but for anyone reading this later; normalClip means a GetVector() call won't return a vector with a magnitude of more than 1 - this is just so you don't get issues where players will travel faster if they press up and right on a keyboard (or whatever).

The GetVector behaviour could do with some work to improve it in this regard I think, maybe 2-dimensional SmartControls?  Anyway if there's any other terms you think need explanation let me know and I'll add them to the documentation or something, I'm pretty blind to what isn't apparent since I often pick terms that make sense to me, and they don't make sense to everyone else...

You're not missing anything, modifiers are definitely on my to-do list but they aren't implemented yet, sorry!

That's all!

If you have any questions, suggestions, requests, or anything at all to say:

And if you just want to tell me I'm awesome, consider doing it with money on my patreon ;) <3

(1 edit)

Saving custom binding is definitely another area I need to look at. Not even all of the important settings are saved in the current version (bindings are, but not toggles/inverts/sensitivity/scaling)

I do have plans for alternative options to player prefs and I've even coded other save systems that I could probably pull into Sinput with very little work.

Update: Sinput now saves all of it's settings as well as custom binding, and on PC it writes to a file instead of Player Prefs too. :)

Hey arvz!

The idea is that eventually you will be able to call LoadControlScheme() passing the name of your scheme or a reference to the scheme asset. Right now tho, as you've noticed the whole initialisation process is... kind of a mess and inefficient too.

Looking into the initialisation process and being able to swap various control schemes are big parts of my priority to-do list but I don't know when they will be done. ngl they are kind of daunting and I can't remember enough off the top of my head about how either works right now to be able to tell you what would be a good way to hack what you want (sorry!)

hopefully I'll get them done soon but for the time being sub-optimal messy rubbish is the best option (and heads-up if you do have multiple control schemes now, player custom bindings for them are probably not gonna be saved reliably)

aaaaaaah I wish this bit worked for you but it's just one of the little corners of the system that hasn't been worked on enough yet ^_^;

(4 edits)

Common Mappings

How common mappings work

Common mappingsare located at Sinput/Resources/CommonMappings in your project, and for the most part, you can ignore them.

Common mappings are assets that describe button/axis mapping for various gamepads on various operating systems. Sinput will try to check all of these for matches with connected gamepads to maximise the possibility of a gamepad working without a player having to set up custom binding. This is going to fail sometimes, but so long as you give players the opportunity to rebind their controls they will still be able to use any gamepad that unity can detect to play your game.

You can make new common mappings for gamepads that sinput does not yet support so that those gamepads will work out-of-the-box with your game.

If you do make new common mappings, please consider sending them to me so I can include them in future versions of Sinput :)

Pad matching process

Pad matching is determined by operating system, gamepad name, partial name, and whether the common mapping is a default.

A common mapping is used for a gamepad if they match, the priority for matching is determined by;

  1. An exact name match from the names list.
  2. The gamepad name contains a match from the partial names list.
  3. The common mapping is marked as default.

It will never match if the operating system running the game doesn't match the common mapping.

Button setup

In this tab, you match up common gamepad inputs to the button indices that unity detects, and provide a display name. 

Axis setup

In this tab you match each of the gamepads axis to common gamepad inputs, and specify how the gamepad axis behaves (clamping, inverting, how far the axis value needs to go to count as a 'press' when treated like a button).

Generally, for most axis you are going to want a setting that will give a value of 0 when resting, and goes to 1 when fully pressed/moved. And for inputs like LSTICK_LEFT where the value for the full left stick's X range is -1 to 1, you will want to clamp it.

Gamepad Debug scene

Included in the project at Sinput/Utilities is a scene to help debug gamepads, it uses displays the full state of all connected gamepads, I use this when building the common mapping for a gamepad - you can identify which buttons/axis are which, and the value ranges of different axis.

Honestly it's pretty confusing to set up mappings from this, but you'll know if you get it right if your gamepad works to play the game without having to set any custom binding in-game.

(5 edits)

Virtual Inputs

Virtual Input Explanation

Virtual inputs are for anything that isn’t a keyboard, mouse or a gamepad that you want Sinput to check. Just add a virtual input to a control, and then you can set it’s values from inside your scripts using these SinputSystems.VirtualInputs functions;

SetVirtualAxis(), SetVirtualButton(), SetDeltaPreference()

Setting an axis value will automatically set the virtual input’s button state, and vice-versa.

Touch Controls

Sinput includes prefabs for touchscreen buttons and analogue sticks, you can find these in the TouchControls folder.

The touch control prefabs require minimal setup; just specify which virtual inputs they effect, and make sure you have listed those virtual inputs in your control scheme.

(3 edits)


Rebinding scene explanation

Sinput includes a scene that can be included in your game to let players rebind their controls, You will need to handle loading the scene from your game, and deciding what happens when the 'Quit' button is used.

Honestly, this is system kind of a mess behind the scenes so if you want to study it in order to make your own rebinding interface you might have trouble if you aren't familiar with how Sinput works internally. I'm working on simplifying it but for now, this is it (sorry).

If you have any feedback on this scene or what it's like to integrate, please let me know! I think every game should let players rebind their controls so if I can do anything to make it easier for you to include this I'd love to know :)

Rebind Menu Settings

You can specify extra settings which appear at the top of the rebind menu with the RebindMenuSettings asset (select via the menu with Sinput > Rebind Menu Settings). You can use this to expose overall mouse sensitivity, which controls can be set as toggling, which smart controls can be inverted, and create sensitivities for groups of smart controls (e.g; You can create a "Look" sensitivity which effects both "Look Vertical" and "Look Horizontal").

You can also just disable these settings entirely if they are not applicable to your game (but I would strongly recommend you consider what might be useful to your players, these features can make a difference for how accessible your game is to play).

(4 edits)


Basic Functions

GetButton(), GetButtonDown(), GetButtonUp()

These work just like the regular unity input button checks, but they can be used reliably for analogue inputs and not just buttons.

GetAxis(), GetAxisRaw()

Again, these work just like you would expect. And work for inputs with analogue or binary values.


Performs several GetAxis() checks returns the results in a vector. Just a time saver for you really

eg; movementInput = Sinput.GetVector("Horizontal", Vertical");

Multiplayer Input

For every input check, you can optionally pass an InputDeviceSlot value, by default this will be the 'any' slot which checks ALL devices, which is ideal for single player games. But if you want only input from the 2nd gamepad, or just the mouse, you use those slots to filter your input checks.

This means you can simply code multiplayer input by having a single player script, where the instances just have a different slot to check.

To get a player's slot, I recommend using:


This works just like GetButtonDown() but instead of returning true or false, it will return the InputDeviceSlot of whichever player pressed the control. You can use this for things like a 'Press A to join!' screen. If there are no presses this frame, it will just return the 'any' slot.

Menu Inputs

Sinput has some functions to make quality menu navigation easier to code:


This will return true when a button press is detected, and if the button remains held long enough, the function will begin to return true again periodically. This means you can make menus where players can hold a button down to keep scrolling, but it won't start scrolling too soon. You can set how long the wait before repeating and how long between each repeat is with Sinput.buttonRepeatWait and Sinput.buttonRepeat.


This will reset all controls (or just controls for a specified slot) for a time, and all Sinput checks will return false or 0 until that time has passed. You can pass 0 if you want to reset inputs for just the one frame like the usual Input.ResetInputs()

You should call this whenever you detect a menu item selection to prevent the player from unintentionally making more selections too quickly.

Toggle Controls

SetToggle(), GetToggle()

Any Sinput control can be set to have toggle behaviour, which makes it so GetButtonChecks will behave as though the control is pressed even after it is actually released, and until it is actually pressed again. You can use this to make it so controls that would otherwise need to be held down (eg crouch) can be instead toggled on/off by the player.

I would strongly advise you expose this option to your players for any control that might need holding for a prolonged period; some players can't press a lot of buttons at once, some may find it strenuous to hold a button, and most keyboards don't support too many buttons being held at once anyway so if you're porting gamepad code it's worth keeping in mind.

If you have a control that may or may not be a toogle and you need the actual value, you can use these functions;

GetButtonRaw(), GetButtonDownRaw(), GetButtonUpRaw()

GetButtonDownRepeating() doesn't have a 'Raw()' equivalent because it ignores a control's toggle setting (I can't think of a good reason it should, if you think adding this behaviour is worthwhile let me know!).


You can set the overall mouse sensitivity that Sinput uses simply by assigning it;

Sinput.mouseSensitivty = 0.5f; //makes mouse movement half as sensitive

In addition to that, you can use the following functions to set the scaling of smart controls (note: this won't work for regular controls).

SetScale(), GetScale()

It's worth keeping in mind, all axis values returned by a smart control will be multiplied buy it's scale, including mouse movement which may have already been scaled by the mouseSensitivity setting. (I'm not sure if this is ideal and I'm still thinking on a better system)

Axis inversion

Smart controls (again, not regular controls) can have their axis values inverted simply using;

SetInverted(), GetInverted()

Framerate Independent Inputs

This one is a little tricky to explain, but put simply, some GetAxis() values you might want to multiply by Time.deltaTime (eg buttons, gamepad sticks), but others you do not (mouse movement).

As an example, think of aiming in first person, an analogue stick in one place will return a constant value every frame - you can multiply this value by deltaTime and turn the first-person view by that much. It doesn't matter if the framerate (and therefore, the deltaTime) fluctuate.

But if you try to do this with mouse input it could be significantly less precise depending on how consistent the framerate is - you will want to turn the first-person view by exactly how much the mouse was moved without the framerate being an influence.

For the most-part, you should be able to get by without worrying, just use Sinput to check a control and you won't have to worry if the value is coming from a mouse, a gamepad, or a keyboard - but for important things like first-person aiming or moving an in-game mouse pointer you will notice (or at least, you'll feel) that the controls are a little off if you don't have separate behaviour in your scripts for these different types of controls.

For that purpose;


If this function returns false for a control, that means any GetAxis() value for that control should NOT be multiplied by Time.deltaTime this frame. (I specify this frame, because the player might switch to gamepad control the next, or maybe they are using both. Sinput is hecka versatile you know ;p)