28 February 2021

Week 4, game 2: Ghost and Hostage

After several setbacks, I've finally completed another new game! You can play it here:

https://dgalga.itch.io/ghost-and-hostage


Brief gameplay video:


The basis for this game idea is the cloaking and anti-terrorist/government operations featured in the Ghost in the Shell series. (Video omitted for copyright content, but check out the series if you're interested!)


There's far too many concepts in the above video (remote hacking and possession, coordinated defensive action, coordinated team action, etc) for me to cover in one 3 hour prototype at my current skill level. So, I also focused on what I can recall enjoying most from my time playing an old multiplayer mod called NEOTOKYO:


NEOTOKYO also focuses heavily on squad tactics, but teamkills (your teammates killing you or you accidentally killing your teammates) are a thing, so I actually spent most of my time in the game going off on my own. It was the feeling of stealthily lone-gunning an area that I was hoping to recapture with my new prototype.


I don't think I was successful. As you can probably tell in the gameplay video of Ghost and Hostage, it's easily possible to lead all of the enemies in the level away from the hostage and the main path. This is because the enemies can respond to your gunshots, but don't patrol or return to their original positions. I believe that a modicum of coordination or independent action on the part of the enemies would make the game far more interesting and challenging. Unfortunately, I ran out of time to test this.


The most important aspect, to me, is the enemy pathfinding. I borrowed a solution from the following site and adapted it a bit:

https://www.davidepesce.com/2019/11/19/godot-tutorial-how-to-use-navigation2d-for-pathfinding/


After that came the invisibility. I did find this

https://gamedevserj.github.io/godot-invisibility-shader-tutorial.html

However, I couldn't get the same shifting/murky effect. I did get as far as making my player object disappear, so I mixed in some code from this shader on outlining an object:

https://godotshaders.com/shader/2d-outline-stroke/

and, mixed in a little from the Action RPG tutorial series by HeartBeast to arrive at this shader code:

shader_type canvas_item;

//variable to allow disabling and re-enabling shader:
uniform bool active = false;

uniform vec4 line_color : hint_color = vec4(1);
uniform float line_thickness : hint_range(0, 10) = 1.0;

void fragment()
{//need previous color to revert to!
    vec4 previous_color = texture(TEXTURE,UV);
    vec4 screenTexture =  texture(SCREEN_TEXTURE, SCREEN_UV);
    COLOR =  screenTexture;
    
    vec2 size = TEXTURE_PIXEL_SIZE * line_thickness;
    
    float outline = texture(TEXTURE, UV + vec2(-size.x, 0)).a;
    outline += texture(TEXTURE, UV + vec2(0, size.y)).a;
    outline += texture(TEXTURE, UV + vec2(size.x, 0)).a;
    outline += texture(TEXTURE, UV + vec2(0, -size.y)).a;
    outline += texture(TEXTURE, UV + vec2(-size.x, size.y)).a;
    outline += texture(TEXTURE, UV + vec2(size.x, size.y)).a;
    outline += texture(TEXTURE, UV + vec2(-size.x, -size.y)).a;
    outline += texture(TEXTURE, UV + vec2(size.x, -size.y)).a;
    outline = min(outline, 1.0);
    if(active)
    {
        vec4 color = texture(TEXTURE, UV);
        COLOR = mix(screenTexture, line_color, outline - color.a);
    }
    else
    {
        COLOR = previous_color;
    }
}

I don't fully understand shaders yet. I think I get the basics of what this code is doing, but I don't trust myself to fully explain it yet. Basically, this shader is using the color of the background to overwrite the color of my sprite, effectively hiding it, while drawing a line around the outline of the sprite. I think.


Finally, there was the issue of making sure the enemies cannot see the player through objects. This was a pickle, because I initially started out using a raycast2D scanning thing that looked like a Cylon scanning the environment.

https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/4430159a-24ce-4291-8254-173eb8dbfebb/d1nl1ht-772fb2cc-9351-4a15-9aed-515315bcbbee.gif?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOiIsImlzcyI6InVybjphcHA6Iiwib2JqIjpbW3sicGF0aCI6IlwvZlwvNDQzMDE1OWEtMjRjZS00MjkxLTgyNTQtMTczZWI4ZGJmZWJiXC9kMW5sMWh0LTc3MmZiMmNjLTkzNTEtNGExNS05YWVkLTUxNTMxNWJjYmJlZS5naWYifV1dLCJhdWQiOlsidXJuOnNlcnZpY2U6ZmlsZS5kb3dubG9hZCJdfQ.DPPqg7T25hxrjF6xy8c4nNvp_XB8uaJGAQcXdYOhkHU


After fiddling with this scanning idea for far too long, I gave up and adapted this solution to fit my needs instead:


Ghost and Hostage is lacking alot, but it's better than the project I failed to finish for week 2. I'm a little disappointed with myself that I failed to put out 4 games in 4 weeks, so I'm going to do my best to ensure I get 3 uninterrupted hours to finish something playable this week. Expect something next weekend!

21 February 2021

Last week was hell, taking the day off

Ok, (short) story time:

At some point early last week, the CO2 alarm in every apartment in my building went on and stayed on for about 2 hours. Now, Austin was frozen over, and there's still covid, so there was nowhere to go and nothing to do. I sat on my couch with my old college laptop, put earplugs in my ears, prayed the electricity would stay on, and tried to figure out what to do with myself.


Long story short, I started an RTS prototype based on a game I no longer have access to called Susume Tactics:

https://www.youtube.com/watch?v=nNh2xjd27_8

 

Unfortunately, I can't tell you much more about the project. With school closed and so much shut down, I transitioned to spending most of my free time each day working on it. It helped with my anxiety over figuring out sponge baths, my shrinking supplies, my growing pile of clothes, the possibility that my water wouldn't return when the freeze broke. Then, the freeze broke, and just like that my motivation was gone.


I'm not sure exactly how much time I spent on this project. I know I wasn't close to finished, and that 3 more hours won't change that. I know I've slacked on my school assignments and my exercise. So, as part of trying to get myself back to somewhere stable, I'm taking the rest of today off. Next week, I'll be returning to the whole 3 hour project in a week thing.


Until next time.

14 February 2021

3 hour project Week 2: Not complete

For this past week, I decided I would try to use my 3 hours of game development time to tackle a new idea. A shooter that uses mouse aim. Somehow, I've never tried to make this kind of game before.


I was able to implement most of the mechanics before falling short:

Titled "Bugsnipe", the above project was still a little confused in terms of what I wanted it to be. The original idea was something of a stealth shooter focusing on a rogue rocket-launcher-wielding soldier taking on some tanks. Anytime the soldier fired his rocket-launcher, the tanks would be alerted to his position and the player would have to duck into high-grass to avoid being swarmed.


I switched the tanks to bugs after deciding I didn't want to deal with tank turrets or making WW1 style tanks. I then got attached to the idea of there being 2 bug factions, and spent probably a little too much time trying to figure out how the player would impact a little bug war going on in the center of the play area. I started creating art assets first, and spent too much time on that as well. By the time I actually finished importing assets into Godot and began coding, I had 40 minutes left!


On the plus side, I learned 2 things I really like. The 1st is a method of having a player rotate towards the mouse position with a small amount of delay or smoothing:

var Mouse_Position = get_local_mouse_position()

self.rotation += Mouse_Position.angle() * smoothing

source:  https://www.youtube.com/watch?v=iOYv4HLWDh0

 

The last time I tried something like this, I had to use the function .look_at() for the mouse position. look_at() is fine, if you want something to rotate and look at something else, like the mouse cursor, immediately. However, it's not really designed to be tinkered with too much. get_local_mouse_position().angle(), on the other hand, can be modified fairly easily. The result adds a bit of weight to turning, which I like in this case.


The 2nd thing I learned was that it's absurdly easy to add a custom mouse cursor to your Godot game. It's right under Display in Project settings:

 

I didn't finish Bugsnipe in 3 hours, and that's OK. According to the rules for this little self-challenge, Bugsnipe will now be set aside until the end of the month. I'm still free to return to it next month if I should decide I want to finish it. In the meantime, I think I have a good foundation for a top down shooting project to build on.


I'm not sure yet what I'll try next week. If this past week taught be anything, it's that the design and research that occurs before I begin development could easily expand into 10 hours or more if I'm not careful, and I'm already pressed for time! So, whatever I decide on, it's gotta be small and simple. Or, build off what I already know (and have example code of), at the very least.


Until next week.

06 February 2021

I'm back, with a plan to produce a game in 3 hours every week

 Happy new year! It's been a little while, and there've been some changes. To keep it short: I'm back in school, I don't want to stop making games, I don't have alot of free time, and I hate the idea of having to put down a large project for extended periods. So, starting this week, I've decided to attempt to produce 1 new game in 3 hours every week until the end of my current semester. 

 

I'll be posting to my blog after each game is "finished" (running in a browser). If I fail to complete an idea in one week, I'll post anyway and then set the project aside for a month. If I ever fail to come up with a decent idea, I'll join a 1 week or less game jam for inspiration.

 

To start things off, here's a Flappy Bird clone possibly staring a character from Steven Universe:

https://dgalga.itch.io/fly-through-the-storm-wind


I intentionally decided to start with a super-simple design. The project took me about 152 minutes in total, and the majority of the code is all in the player.

 

For the uninitiated, Flappy Bird was a 2013 mobile title that blew up beyond anyone's expectations. It looks like this:


I've literally never played Flappy Bird in my life, and I was not interested in directly copying it. However, the potential of a system that can be engaging while requiring little more than button taps has started appealing to me recently, so I decided to take a shot at it.


I didn't really do anything to reference any part of the design of Flappy Bird. I opened a blank project, setup a basic player character, and tinkered until things felt "OK":

func _physics_process(delta):
    fail_check()
    #constant gravity
    if !calm:
        velocity.y += fall
    #rise when flying
        if Input.is_action_just_pressed("ui_select"):
            animplayer.play("flap")
            velocity.y = 0
            velocity.y -= rise
            velocity.x += forward
    elif calm:
        velocity.y += fall * 2
        if Input.is_action_just_pressed("ui_select"):
            animplayer.play("flap")
            velocity.y = 0
            velocity.y -= rise / 2
            velocity.x += forward / 2
In the above script, the player is always falling thanks to velocity.y += fall (down is positive on the Y axis in Godot, while up is negative, so adding to a variables y value before applying it to a character causes "falling"). Anytime the player taps the Space key on a keyboard, the player moves upwards and forwards for a very, very short duration. After a great deal of tinkering, I found that constantly falling at a rate of about 1 pixel, while possessing the ability to rise at the rate of about 50 pixels and move forward at a rate of 20 pixels, felt the best.


To make things a bit more interesting, I decided to create a "zone of calm" in my game. The idea was that the player character, who I'll henceforth refer to as Lapis, is flying through a storm. There is a calm space within the storm where there is no wind, but flying takes twice as much effort. This is what the calm variable above is referring to: an object outside of Lapis has the ability to reach into her script and set calm to true or false. While calm is true, flying is twice as hard as gravity is unchanged but Lapis' ability to rise up and move forward is divided in order to be more difficult.


The rest of the important code in my game is associated with the "wind". I wasn't sure how to create wind other than by using static blocks, and I clearly didn't leave myself alot of time to experiment, so static blocks is what I went with. Each block has the ability to reach into Lapis' script and move her in a given direction, with the larger blocks being twice as good at this:

func _on_Gust_body_entered(body):
    print("boop")
    body.velocity += dir_push * forward_push

The above function fires when the player touches "wind". dir_push is a variable that controls what direction the player is moved in, and forward_push controls the power of that change of direction.  The smaller wind gusts are set to 100 power, while the larger are set to 200. I still don't think these values feel perfect, but they do feel "good enough", so I settled.

 

On a side note: I totally forgot these objects are set to print the word "boop" on contact with the player. Oops.


That's really all the important code for my new game. Give it a shot and let me know what you think.

Piecemeal Jack - post 4 - wrap up

 I'm calling it quits on Piecemeal Jack for now. This is as far as I got: I built everything I had planned, to some extent, and the resu...