Description


A puzzle game about getting socially awkward slimes to meet. They slide around a hexagonal grid in groups, conforming to the kind of moves that keeps them happy.

Each level consists of an arrangement of slimes, and your goal is to get two Loving Slimes (the orange ones) to meet each other. This is made difficult by the restrictions of each slime. For example:

  • Slimes get too nervous to be in crowds of more than 4.
  • Slimes don’t have the energy to move without a connection to a Heart Slime (the pink ones).
  • Heart Slimes need to settle a slime behind them to move (turn them grey).
  • Settled Slimes cannot move.

This project has reached an alpha stage where the core systems are in place, the core rule set has largely solidified, and the main gameplay loop is complete. Plans are in place for further content to add, and proper visuals to replace the current placeholder ones.

00:00
-00:19

Goals and Achievements


Programming

Systems

The first goal was to create a highly versatile rule based selection and move system. This was successfully achieved by:

  • Decoupling the logical side of the slime from the visual representation.
  • Decoupling the rules from the effects caused by their completion for greater code reuse.
  • Creating interfaces for rules and effects that were not attached to any given slime to allow broader classifications, and make changes to the rule and effects set very quick and simple.
  • Utilising the existing board state cloning to apply changes to the board for move validation without ruining the actual board state.
Slime movement rule set tool
Slime movement rules tool
Slime selection rule set tool
Slime selection rules tool
Slime logical response set tool
Slime logic responses tool
Slime humble response set tool
Slime humble responses tool
Slime Simulation

The second goal was to simulate the slime and make it responsive to player actions. It has been implemented to react independently to movement forces, and with it’s current implementation can be easily expanded on to respond to the mouse cursor’s movement, have separate slimes move as one entity, and dynamically change the slimes connected as one entity.

They have been simulated using a simple soft body physics model, where various points along the slime are connected in a network of springs. The sprite gets distorted to match the simulation, and torsional springs were made to have slimes keep their shape. This simulated mass is childed to the main slime object to make responses automatic and prevent features like the expression from being forced to use it.

00:00
-00:03
Unit Tests

To ensure changing rules around wouldn’t cause bugs or have unexpected behaviours, each one has been unit tested. Some core systems have also been unit tested. Adding these tests is quick and simple thanks to decoupled code design. Here is an extract of a rule’s unit test code:

[SetUp]
public void Setup() {
	hexagonGrid = new HexagonGrid<CellData>();
	selectedHexagons = new List<CellData>();

	movementRuleContext = new LogicMovementContext() {
		hexagonGrid = hexagonGrid,
		selectedCells = selectedHexagons,
		currentMovedDistance = Vector2Int.zero,
		totalMovement = Vector2Int.zero,
		direction = Vector2Int.right
	};

	slimePrecedesSlimeRule = ScriptableObject.CreateInstance<SlimePrecedesSlimeRule>();
	slimePrecedesSlimeRule.precedingSlimeType = SlimeType.Heart;
	slimePrecedesSlimeRule.followingSlimeType = SlimeType.Loving;
}

private CellData CreateCell(Vector2Int position) {
	CellData cell = new CellData(position);
	hexagonGrid.Set(position, cell);

	return cell;
}

private CellData CreateSelectedCell(Vector2Int position) {
	CellData cell = CreateCell(position);
	selectedHexagons.Add(hexagonGrid[position]);

	return cell;
}

[Test]
public void PrecedingSlimeWithNoFollowingSlime() {
	CreateSelectedCell(Vector2Int.right).type = SlimeType.Heart;

	Assert.False(slimePrecedesSlimeRule.CheckRule(movementRuleContext).Passed);
}

[Test]
public void MultiplePrecedingSlimesWithMixedCorrectnessOfFollowingTypes() {
	CreateCell(Vector2Int.zero).type = SlimeType.Loving;
	CreateCell(Vector2Int.down);
	CreateSelectedCell(Vector2Int.right).type = SlimeType.Heart;
	CreateSelectedCell(new Vector2Int (1, -1)).type = SlimeType.Heart;
	CreateSelectedCell(new Vector2Int (1, -2)).type = SlimeType.Heart;

	Assert.False(slimePrecedesSlimeRule.CheckRule(movementRuleContext).Passed);
}

And here is a view of the test runner:

Unit test runner

Design

Rule basis

The rules designed to create a unique feeling sliding puzzle out of a hexagonal grid. To make the most use out the properties of a hexagonal grid, neighbour and group based rules were designed. To increase the possibilities for puzzle challenges and make the mechanics more interesting, sliding was done in groups.

Rules were designed to encourage movement around the board without allowing completely free range and without creating hard barriers. This was primarily achieved by creating the Heart Slime (the pink ones) that others need to connect with to move, and having the Heart Slime be difficult to move, but not so anchored it overly limited how far connected slimes could spread.

Rules were also designed to be versatile. For example, the Settled Slimes (the grey ones) cannot move, making them difficult to work around. They do however count towards a connection to a Heart Slime, making them useful to have within a group when positioned correctly.

Slime theming

The choice of slimes was deliberately chosen for three reasons:

  • Their squishy nature making smooth sliding on a hexagonal grid possible.
  • Their exagerated expressions give an intuitive and diegetic way to express certain rules.
  • How they bring life and expressiveness into an otherwise very dry abstract puzzle, to give the game some appeal outside of hardcore puzzle fans.
00:00
-00:28

Project Details


Role: Programmer and Designer

Group Size: 1

Game Engine: Unity

Code Language: C#

Project Purpose: Hobby