Getting close to the point where this can technically be called a game. Right now there’s no goal so it’s just a simulation of rays bouncing around. What I need is a target. And maybe a couple other things…
- A laser target which indicates whether it’s being hit by a laser.
- Mirrors (refraction doesn’t change the angle enough).
- Light absorbed by static bodies, including the viewport walls.
Since my current Godot project is called “RaysAndBlocks” it makes sense to split off again… I wonder if my approach to organizing these is, well, wrong. I’m basically building up one prototype but retaining snapshots as separate projects (in addition to git commits).
I guess I could return to these little prototype projects easily if I want to experiment with, say, a different way of moving blocks around.
Plus, the whole point of prototypes is not to have to worry about things like project structure and naming too much so let’s not worry about it.
I’ll do reflections first in RaysAndBlocks then spin off RaysAndSensors or something like that.
Timesheet Spreadsheet #
Side note: I’m tracking my time in a simple Google spreadsheet for now. There’s a shortcut for getting the current date time.
Ctrl + Alt + Shift + :
That way I can just hit the shortcut when I start and when I finish and then output the difference—the duration of my work block—in another cell.
Side side note: people seem to think that the use of em dashes is an indication that something was written by AI. Well, I like em dashes so I’m keeping them.
Reflections #
I’ve done refractions already so this should be easy… right?
Creating a Mirror scene which is much the same as Block in terms of shape and dragging behaviour. After doing some reading it looks like the best way to give the same functionality to both is to create a new class that extends Node and provides the dragging functionality, then add an instance of that Node to each of Block and Mirror.
I added two mirrors (light grey). Currently, the ray refracts but doesn’t seem to register the exit. I think that’s because I have some code that’s expecting a Block class. It’s probably failing because it’s getting Mirror instead.
Creating a Draggable Scene #
I want to add draggable functionality to both Mirror and Block so I’m making a Draggable class which extends Node. This is proving tricky. I don’t want to have to write code to tie in functions like _process_physics()
and _input_event()
with Draggable. I’d like to just add Draggable as a child node and it does what it needs to the parent.
I also don’t want to use inheritance for this… it seems like a composition thing. But I might be making this unnecessarily difficult.
…
Okay. That took some doing. I now have a Draggable that extends Node. It can do most of the processing on its own but it can’t receive input events based on the CollisionShape2D automatically so the Mirror/Block class delegates that event to Draggable.
Like this:
func _input_event(viewport:Viewport, event:InputEvent, shape_idx:int) -> void:
($Draggable as Draggable).input_event(viewport, event, shape_idx)
I also created a DragManager singleton which the Draggable instances register with. That takes a bunch of dragging logic out of Main.
Okay, now I can work on reflections.
Now I can finally change the direction of the light more than the little wiggle allowed by the rectangular prism.
This makes it more interesting to play around with things, too…
Temporarily widened the prisms so I could get a second internal reflection and I got internal reflections forever.
It’s looking pretty good, I think.
Next Problems #
When blocks are right next to each other—and they probably will be—that last laser is starting from inside the mirror. The mirror ends up being completely ignored.
There is an option to have collision detection from inside an object. Big downside is the normal will be a zero vector.
One solution might be to perform collision detection with hit_from_inside
enabled. If there is a collision and the ray started from inside the shape, the normal will be the zero vector. If the zero vector is detected then walk back a few paces and cast another ray and only test against that body that had the collision from inside. That’ll give us a collision point and a normal. Probably best not to try to draw the laser beam between those because it’ll probably be backwards. Backwards but also very tiny.
I’ve been thinking I’ll probably have a glowing light effect wherever laser beams collide with bodies, partly because it’ll look cool and partly because it’ll hide errors like these.
A second possible solution? Use two different collision shapes. One of them is to handle the laser beams and the other, slightly bigger, is used for blocks running into each other. The extra padding will ensure the laser beam collision points are never too close together. Downside is, I gotta go through the extra work of defining two collision shapes and it’s not going to look as good if the blocks have an invisible force field around them.
This pictures a second problem. That 2i ray should’ve reflected off the inside of the block but instead it goes sideways. I’m not sure why it’s doing that but it looks like the refraction code got executed instead of the reflection code.
Okay, that one was actually pretty easy. I checked the case where that reflection/refraction branch occurs and I wasn’t testing for -π but only for π. Here’s what it looks like after the fix: