Making a light-based roguelike. I want the combat to revolve around the cursor and its physics.
Here’s a quick look at what I’m working with. 2D, top-down, cursor-based combat, with some physics-based lighting.
I want the player to be able to do recon with the cursor’s light effects, but I also want to make it so the player’s cursor (or at least, the part of it that actually lights up and draws the lightsword thing) to stop when it collides with a wall.
Ideally, it would detect where the mouse is. Then, if there’s a collision with the physics layer of the tilemaplayer, do blah blah blah. I have ideas for that part, but I just don’t know how to detect that collision in the cleanest way as tilemaplayer doesn’t seem to have any signals tied to this.
I thought I’d make the lightsword element itself a CharacterBody2D, in anticipation of being able to switch its movement from using direct position assignment to the move_and_slide() function on it.
Here’s the connected method I use on my LightSword node:
func _on_collision_hitbox_body_entered(target: Node2D) -> void:
#print("Collision detected between the cursor and: ", str(body))
var speed = data[0]
if target is Enemy:
var speed_multiplier = clampf((speed/750), 0.0, 1.5)
var output_damage = (speed_multiplier * damage) + damage
if speed_multiplier >= 1.5:
target.inflict_damage(output_damage, true)
#print("Critical hit!")
else:
target.inflict_damage(output_damage, false)
elif target.collision_layer & (1 << 0):
print("Target is on layer 1 (Wall)")
elif target.physics_layer_0 & (1 << 0):
print("Target is on layer 1 (Wall)")
I don’t know about collision detection with the mouse because the cursor doesn’t actually have a hitbox. What you could do is get the mouse coordinates and use local_to_map() to convert the local mouse coordinates into local tilemap coordinates like this:
var mouse_pos = get_viewport().get_mouse_position()
var local_pos = tile_map.to_local(mouse_pos)
var tile_coords = tile_map.local_to_map(local_pos)
This would return a Vector2i like this: (0, 1).
If you want to perform actions depending on what tile the mouse is in, you can do this by checking the atlas texture of that specific tile if it matches the one you need specifically.
I made a node that tracks the cursor and moves to it, and it carries with it all the cursor logic and graphics. Turns out I can detect enemies and damage them using the hitbox I attached, but for some reason tilemaps seem to work differently.
I’m looking for a way to use signals to automatically trigger things for me and make things cleaner. Since I got this hitbox system to work, I thought I’d use it for the wall collisions too. But you do make a good point with your code, about checking the position of the cursor and mapping it to a coordinate.
I made a custom occlusion layer for the light so that it would properly wrap around walls visually. My textures don’t follow the grid exactly, too. So I guess I’d have to make a new layer or separate tilemap for the mouse collision, and I could make it much finer (4x4 pixels instead of 16x16, for instance) to capture the minutiae.
But then, with my current setup, I’d have to actually write the code for what the lightsword does once it hits the wall, because I want it to stick to the wall and slide up and down based on where the cursor is behind the wall. A smooth transition.
But! I think I have an idea. I realized while replying to you that the move_and_slide() code for my player is based on a lerp() rather than direct assignment. The move_and_slide() method does exactly what I need, but it wasn’t working because I was using direct assignment for my lightsword.
I will be trying to use a modified version of my player movement code for my lightsword, where instead of accelerating based on a normalized input vector and then using move_and_slide(), it’ll be lerped to the mouse position, and have its velocity read, and then used for the move_and_slide() method. Then I just have to set its collision detection to be the same as the player’s.
I can still hit enemies, but now I collide into the player. That’s fine, I can fix that. The bigger issue is my cursor_trail that uses the cursor position to draw a line2D to it. I think I just have to make it change based on the actual position of the lightsword instead, so it doesn’t draw through walls.
And then I need to make the brightness and size dependent on the actual measured speed of the lightsword, instead of a simple A-to-B vector difference approximation per frame.
I also need to tweak my “in between frames enemy hitter” code. I added it so that enemies could be hit, even if the hits were missed by the cursor moving too fast between frames. But it used the cursor position, so you can still hit enemies behind walls if you put your cursor on them. I guess I can use the actual lightsword position instead.