Ahead in development, behind in business
Updated: Aug 16, 2019
I've got good news and bad news. Good news first.
I'm 1 weekend ahead on my project. The three initial challenges I set aside for myself, making a callable function for player damage (to be filled out when damage becomes important), handling players falling off levels, and re-spawning the player after they've fallen, proved so trivial to implement that I completed all 3 in about 30 minutes. Holy fuck.
The reason I'm only 1 weekend ahead on my schedule is because the 3 challenges I assigned myself for next weekend, the next 3 traps (I consider tiles that can force a player to fall to be "traps"), proved tricky to implement. The 3rd trap in particular was directly changed from the original design in favor of something better fitting my goals.
Originally, I intended for one of my traps to be a "shot trap". Designed to shoot out projectiles at regular intervals, the shot trap would provide an obstacle capable of impeding huge areas of player-passable terrain. Unfortunately, this kind of trap presented 2 problems I wasn't a fan of. 1st, extra sprites would be needed to align with all 4 wall directions, adding cost to a budget I've been working to keep tight. 2nd, every aspect of the shot trap, from the projectiles to the trap location and attack angle, would require a higher level of development investment to ensure the player remains aware of the danger when in melee with foes on all sides.
This is what I implemented instead of the shot trap:
I call this the push trap. It's big, so it's hard to miss. I can re-use and alter the coloring of existing wall assets to define its appearance, thus ensuring no sprite budget increase. I could do even more in code, and have the push trap vibrate or shake before launching itself at the player.
I say "could", because I didn't have time to get any of that stuff working. It took all of my free time on Sunday just to get to what you see now.
When I started on the push trap, I wanted to use a Raycast to check when the player was in front of it. Raycasts in Godot couldn't get me the information I wanted, so I had to settle for a collision box (the light-blue box the player crosses to activate the trap).
The next issue was actually just making the push trap push the player. As you may be able to tell from the gif, this remains an unsolved problem. When the player comes up from below the trap, the trap correctly pushes the player. However, when the player comes down to the trap from above, the trap moves both forward and upward instead of just straight, and then gets stuck at half the distance it was supposed to travel!
I believe the weird behavior in the push trap is due to a quirk in the way pivot points work for nodes in Godot. All nodes have a pivot point in the upper left side, and this pivot point may only be moved on visual (sprites, color blocks, etc) nodes. So, unless I want a sprite to be the root node for my player (not advised), I'm stuck with scripts that are getting the upper left portion of the player instead of tracking the player object from his center.
This is the way I understand it, anyway. I could easily be wrong.
This is the code I used to try and move the trap in a straight line if the player is present:
if player_in == true and return_time == false:
move_direction = get_direction(player_pos) * move_speed
elif player_in == false and return_time == true:
move_direction = get_direction(ori_pos) * retreat_speed
if position == ori_pos:
return_time = false
position.x = clamp(position.x, -ori_pos.x, ori_pos.x)
position.y = clamp(position.y, -ori_pos.y, ori_pos.y)
If the player is in front of the trap, I get the player's position and turn it into a direction to move the trap toward the player (regardless of angle):
var heading = player_pos - self.global_position
var distance = heading.length()
var direction = heading.normalized()
The above direction-getting formula was the biggest headache out of the whole weekend! This is because the latest version of Godot simply offers a .direction() built-in function, but I'm not on the latest version and my past experiences with Unity have dissuaded me from upgrading my engine versions during a project. Ultimately, I was unable to find a Godot-specific workaround, and I ended up trawling for Unity C# code I could convert. I eventually found something like the code above. Well, the original version actually looked like this:
var heading = position - player.global_position
var distance = sqrt(heading.x*heading.x + heading.y*heading.y)
var direction = heading / distance
player.position.x -= (hurt_bounce*direction.x)
player.position.y -= (hurt_bounce*direction.y)
It was only after I completed the above code (which I'm still using as part of my player damage function to bounce the player away from incoming damage) that a Reddit user by the name of Cykyrios pointed out several corrections.
It's silly to have 2 different direction-finding functions in my game, I know. However, considering both scripts do different things, I've decided to retain both for the time being to avoid breaking anything.
Despite how much trouble the push trap caused me, I was in high spirits until I was reminded of something. Here's my bad news:
I made an agreement with my current employer to complete a certification before the end of this year, and I'm only half-way through the training I've been doing.
In order to obtain the certification I promised to get, I will need to step away from this project for a month to study and test. I'm hoping the process won't take more than 1 month. Additionally, in order to avoid wasting my own money, I will need to pass the test the 1st time I take it.
As of now, I'm allocating September as my study month. I've got less than 10 hours of coursework remaining, so the only difficulty will be forcing myself to pay attention. And, finding a testing location. And, testing. I'm not looking forward to it.
Until next week.