Skip to main content

Walls, Sensors, and a Puzzle

·1027 words·5 mins

Today, let’s have objects that block light. Maybe those objects should be called blocks instead of the rectangular prisms I’m currently calling blocks.

Types of objects:

  • Prisms (glass)
  • Mirrors
  • Walls

Each of these may or may not be draggable. They should all collide with each other.

In the future there might be mist or fog or something where light can’t pass through but objects can. And pits or windows where objects can’t go but light can.

Cool. I’ve already done the heavy lifting so that was actually very easy.

I’ll need walls that can’t be dragged and walls that can’t be moved at all (StaticBody2D instead of RigidBody2D). I don’t think I want using one object to push another object since it can’t be dragged with the mouse to be a mechanic.

The code could use some love, though.

The Sensor
#

It’s finally time to detect laser beams. There’s a lot of logic in the Laser scene already but I think that’s where I put the detector logic, too. I’m already detecting collisions with various game objects so if I get a collision with a Sensor then I can notify it directly.

Question is, when do I evaluate the code that counts the number of collisions it has received? When do I zero it?

I mean, right now I only have one laser so I can just check whether there was or wasn’t a collision but I know I’m going to have more lasers in the future.

In the future.

Okay, we have some really ugly debug art and a functional sensor now.

Sensor not triggered:

Sensor triggered:

I’m not sure I can use this to count how many lasers are hitting the sensor but I can do it for active/inactive. Lasers are calculated during _physics_process() on a bunch of different nodes. I don’t have one imperative method that adds reflections and refractions, it’s spread out across a tree of laser instances. So unfortunately, I can’t just set the sensors to zero before I do the calculations and then see how many hits the sensor received after.

What I’ve done for now is set the Sensor’s is_active flag to true when a collision occurs. This happens during the multiple calls to _physics_process(). Then, during the Sensor’s _process() callback I check whether a laser hit the sensor. I use that value to update the “art” (yeah, it deserves to be in quotes like that). Then I set the is_active flag back to false to prepare for the next round.

At this point _physics_process() gets called presumably a bunch of times. If it gets called zero times, actually, I would be in a bit of trouble here. But it gets called a bunch of times and is_active gets set to true at least once before Sensor’s _process() is called again.

I feel … uncertain.

A quick test tells me that exactly one collision is being registered for every call to Sensor._process(). Can I rely on that, though?\

If I implement Sensor._physics_process() I can probably rely on that being called exactly once… but I would have no idea when.

I guess since I’m prototyping I leave it as-is for now and wait for it to stab me in the back down the road. 😁

Possible solution.

What if I keep track of the number of leaf laser nodes. If a laser doesn’t refract or reflect, i.e., it gets absorbed by a wall or a sensor, then that’s a leaf node. Right now the number of leaf nodes will match the number of emitters so it’d be easy to determine when all leaf nodes have been processed. At that point I can execute some code.

That’s when I would record the number of sensor hits and then zero out the sensor again. That would be safe, whether the _physics_process() methods run once, zero times, or a hundred, I’ll always get the same result.

I’ll tuck that in my pocket for later. Right now it’s just unnecessary complexity.

Rigid with Freeze vs. Static Bodies
#

I think the goal right now is to get to the point where I can block a level or two and see if I can make something that’s actually interesting / compelling. You know, fun.

I think I need one more tool in my toolkit for that to happen. I need walls that can’t be moved. The emitter and sensor, sure, I can set those to static bodies. Walls… actually, maybe I don’t need to have draggable walls at all. The player should only ever interact with lenses and mirrors.

Okay, that problem solved itself.

Puzzle Time
#

Simple puzzle. Emitter pointing at the sensor but there’s a wall in the way. The most natural way to solve this would be with three mirrors but here’s a solution that uses internal reflection.

Here’s another solution with just two mirrors.

Those rectangular prisms don’t really do much right now unless you use the internal reflection. They’re too narrow to be very useful at all.

I need to go to the drawing board to come up with actual interesting levels.

I can’t create a catch with a one-laser puzzle. Like, I want the player to try to use a solution that requires two mirrors but… oh, the second mirror is needed where it is. Then they can find out they need to use two sides of the same mirror.

I’m sure I’ll have a couple one-laser puzzles at the beginning to get the training wheels on but I don’t think they’ll be compelling. So. Right now I need to get two emitters to work.

Man, I was way over-complicating it before. I had code in Main._ready() that found the emitter and placed a laser at its location, pointing the right direction. I can just put the laser right into the emitter and everything works fine. Deleting code feels good.

That means I don’t need the Path2D and the PathFollow2D I was using to determine where to put the laser either.

So here’s the solution I have in mind:

But if I start the puzzle looking like this:

That sets the player up for the wrong assumption.