As was foretold, we've added advertisements to the forums! If you have questions, or if you encounter any bugs, please visit this thread: https://forums.penny-arcade.com/discussion/240191/forum-advertisement-faq-and-reports-thread/

[Game Dev] I don't have a publisher. What I do have are a very particular set of skills.

18687888991

Posts

  • templewulftemplewulf The Team Chump USARegistered User regular
    edited January 17
    Kupi wrote: »
    Yep, that's what I found when I went looking for sprite atlassing in Godot out of curiosity, but I didn't get deep into it since I was trying to stay on the rails as far as the tutorial material went. Good to know the capacity's there, even if the approach is a bit more manual.

    This is for anyone else wondering about Godot as much as for you, so bear with me if I'm repeating things you already know.

    I'm confident that 4.x is much better than 3.x, but sprite workflow is still well short of what you'd expect from Unity.

    AtlasTextures have historically not worked well with animation and Tilesets. Make sure you have at least a 4.x version before attempting them with animations; I'm not sure on the status with tilesets.

    There are some, caveats, though. You *cannot* import an AtlasTexture automatically, the way the auto slicer works in Unity. You use the "Texture2D" import setting for sprite sheets, same as any other png. The "TextureAtlas" import setting is used to *create* a spritesheet by importing multiple image files at once, *not* to import an existing spritesheet.
    Some UI has moved around since 3.x, and its discoverability is poor, but everything should work out of the box with these steps:
    1.) Drop an image file like a .png into your project directory; standard "Texture2D" import settings are fine
    2.) Right-click a folder in your FileSystem tab -> Create New -> Resource -> AtlasTexture; save it
    3.) Double-click the new .tres file to load it into the Inspector
    4.) In the Inspector, drag or Quick Load your sprite sheet in the Atlas field
    5.) Click "Edit Region". (This is where it diverges from 3.x. There used to be a "Texture Region" tab on the bottom dock, with some different UI, but now it's all packed into the "Region Editor" popup)
    6.) Change your "Snap Mode:" to "Auto Slice". (Yes, it's under "Snap Mode")
    7.) Click the region that contains your animation frame
    8.) Close the region editor, and your AtlasTexture now has the correct coords for your atlas region. Drop it into Animation tracks or whatever like a normal texture
    9.) Repeat steps 1-8 for *every* frame on *every* packed sprite sheet in your game

    Much like Unity's Auto Slicer, it doesn't work well with particle bursts that have a lot of alpha between each particle. You'll have to switch "Snap Mode:" back to "Pixel Snap" to manually capture those regions, then switch it back to "Auto Slice" next time you need full frames.

    You can see from those steps, getting a list of animation frames from a packed spritesheet requires a *lot* more editor interaction in Godot than I'm accustomed to from Unity.

    So, why is it so laborious? Even though auto slicing packed sprite sheets is the most natural workflow for me, it's not what they intend. They want you to:
    a.) have all your individual animation frames as single assets, then bulk pack them with the TextureAtlas import setting.
    Or b.) have identically sized frames in your sprite sheet, with lots of wasted space (and requiring more planning).
    Or c.) they want you to create a packed spritesheet with external toolchains and pass in a metadata "Atlas File" (e.g. JSON) that specifies the regions

    A lot of the advice online is to take option b.), use standardized frame sizes, which I *hate*, but it does seem to be the lowest friction workflow.

    templewulf on
    Twitch.tv/FiercePunchStudios | PSN | Steam | Discord | SFV CFN: templewulf
  • RoyceSraphimRoyceSraphim Registered User regular
    New year, new me.

    Tried copying someone's speed coding pacman in gamemaker

    game runs find except with collision.

    Not seen in the following code is the collision event with walls setting speed to zero.

    See, if I put place_snapped(64,64), then the player just stops when touching a wall, unable to move away from it

    But if I take it out, the player just passes through walls and goes off the (64,64)

    /// @description movement
    if  (place_snapped(64,64)) 
    	{
    	if keyboard_check(vk_right) && place_free(x+1, y) {
    	
    		direction = 0;
    		speed = velocity;
    
    	}
    
    
    	if keyboard_check(vk_left) && place_free(x-1, y){
    	
    		direction = 180;
    		speed = velocity;
    
    	}
    	if keyboard_check(vk_up) && place_free(x, y-1){
    	
    		direction = 90;
    		speed = velocity;
    
    	}
    	if keyboard_check(vk_down) && place_free(x, y+1){
    	
    		direction = 270;
    		speed = velocity;
    
    	}
    }
    
    if speed > 0{
    	image_speed = 1;
    	
    }else{
    	
    	
    	image_speed = 0;
    	image_index = 0;
    	
    }
    
    
    switch(direction){
    	
    	case 0:
    	sprite_index = spr_dudeside;
    	//image_xscale = 1;
    	break;
    	
    	case 90:
    	sprite_index = spr_dudeup;
    	//image_xscale = 1;
    	break;
    	
    	case 180:
    	sprite_index = spr_dudeside;
    	//image_xscale = -1;
    	break;
    	
    	case 270:
    	sprite_index = spr_dudedown;
    	//image_xscale = 1;
    	break;
    	
    }
    
    
    if keyboard_check(vk_escape){
    	game_end();
    }
    


    I should mention that the video I followed originally put place_snapped() on each VK_check, I wrapped the whole thing in an if statement (based on another web post) and found a similar effect.

  • KupiKupi Registered User regular
    Kupi's Weekly Friday Game Dev Status Report

    I've been alarmingly productive considering that it's a GDQ week. But since I'm still doing engine work instead of creating actual games with it, you could also say in all fairness that I'm just wasting my time. But I'm too stupid and bullheaded to accept that, so onward I go.

    - Moved my unit tests from a console application project into MSTest. Many of my tests are still written non-idiomatically (one test might contain multitudes of cases and assertions related to a specific subsystem), but they hit the same code coverage and now my unit tests show up in the test explorer, so it's an improvement.
    - Accidentally resurrected a number of tests that I must have somehow bypassed because things that had been working for months were suddenly failing. But hey, I identified a problem in an obscure case in the collision detection code and fixed it!
    - Fixed a problem that could allow sprites on the edges of the camera fail to render.
    - Changed how IDs are generated in the system that saves a whole lot of memory on identifying which IDs are available.
    - Discovered, as I was attempting to actually start replacing my test project's content files, that sound effect handling was still in the wrong project file and moved it over.

    ... which leaves me butted right up against actually using my project editor to make content files. Like I always seem to be.

    See you next week.

    My favorite musical instrument is the air-raid siren.
  • RoyceSraphimRoyceSraphim Registered User regular
    http://www.extentofthejam.com/pseudo/

    Advice on getting the space harrier 3d ground effect.

    No where near close to doing anything African with the space harrier concept, but wanted to share the data.

  • HandkorHandkor Registered User regular
    edited January 23
    http://www.extentofthejam.com/pseudo/

    Advice on getting the space harrier 3d ground effect.

    No where near close to doing anything African with the space harrier concept, but wanted to share the data.

    Not long ago I was trying to fake the fake 3D effect but in real 3D in Unreal Engine 5. I still wanted to use some perspective effect so I didn't use an orthographic camera but instead pulled back quite far and used a narrow FoV. The playfield is still full 3D but going left or right moves around a circle making it look like you are only translating but since you are turning the world loops around properly. The space between the camera and the pivot was really important to keep the world looking flat since the camera move more laterally with the player instead of just turning to look at the player. This allows the playfield to stay quite narrow giving you a lot of screens of far background before doing a full loop.

    py1x8jfxkqbp.png

    The ground shader was done with camera aligned horizontal color bands and a distance offset. When you move forward the lines will move in the opposite direction to appear anchored to the ground but when turning you stay on the same color band.

    Edit:

    I uploaded a video example of the camera I just described

    https://youtu.be/3DrRTZl2K4s

    Handkor on
  • KupiKupi Registered User regular
    Kupi's Weekly Friday Game Dev Status Report

    According to my Git history, after two months of effort... my game engine is back to where it was before I started revising things two months ago. By which I mean, you can load up a level where Sonic the Hedgehog jumps around on a bunch of brick tiles. The underlying code and content files changed a lot, but the user-facing behavior is unchanged.

    So it goes with refactoring. At least it runs on way less code and, in several cases, makes creating new content files much easier. After feeling like putting together spritesheets and animations was taking way too much clicking, I added a toggle-switch that makes the auto-detect feature for defining new sprites by exploring the non-transparent pixels of a given texture auto-increment the sprite name, such that I can just type in an animation name, right-click a series of sprites, and have them all named in order. The animation editor likewise knows how to auto-increment through sprite names when adding new frames, so if the spritesheet has a twelve-frame-long animation, I can throw together the spritesheet definition and animation with just a series of mouse clicks.

    I'm making progress on how I want to design the terrain painter I've been talking up at the end of each check-in, so next week I'll probably have something to report on that front. Until then!

    OH BUT BEFORE I FORGET.

    A group named Rawrlab has released a free port of Godot to the Nintendo Switch: https://www.rawrlab.com/godot_nintendo_switch_free_port.html

    It's on a restricted feature set (most significantly, C# and C++ extensions are not supported), but that's miles ahead of where Godot used to be when it comes to porting the Switch (which remains my starry-eyed dream).

    My favorite musical instrument is the air-raid siren.
  • GlalGlal AiredaleRegistered User regular
    Fingers crossed Switch 2 remains compatible with its predecessor.

  • KupiKupi Registered User regular
    Well, this is disappointing. I decided to throw together a stress test in Godot, just to see how many objects I can stick on a single screen before it starts getting framey. I ringed the default viewport in square staticbodies and sent circular rigidbodies bouncing around at a randomized velocity, with no friction, gravity, or linear damping. The circles occasionally bounced straight backward on impact with the wall-- indicating that they were only detecting the collision with the corner of one tile, even when a proper circle-cast should have detected the nearer tile. (I double-checked the dimensions and positions of the wall volumes; they're flush together.) I think (I would certainly hope) that this is because I'm not going the expected route of just using one long rectangle if I want a wall, or that the TileMap object does what I've been working toward in my engine and fuses adjacent bodies together (or just has one collision volume to begin with). But it was jarring to get this result in any case.

    My favorite musical instrument is the air-raid siren.
  • GlalGlal AiredaleRegistered User regular
    Yeah, Godot has had an iffy history with its physics engine. Originally they rolled their own, then they replaced it with the Bullet engine, then in 4.0 they went back to their own. I wouldn't cry too hard for the Bullet engine, my experience with it is that, setting up a ball to bounce with 0% dampening, it would steadily bounce higher and higher, as the ejection from the collision surface added to the total speed with each hop.

    I've not messed around with 4.X's 2D physics much, however I will say that handling character collisions (where you don't necessarily want 100% accurate physics, unless you want your character to sail into the air every time they walk onto a down ramp) and stuff like onFloor detection were a lot more consistent. I suspect still imperfect though, it's a complex nut to crack and Godot can't just bring in a 3rd part closed source dedicated engine to do it for them.

    With 4.X's 3D physics you can install a 3rd party Jolt engine (Asset Lib tab -> Godot Jolt), which from what I've seen is both much faster and more correctly handles mass collisions than Godot's current one.

  • RoyceSraphimRoyceSraphim Registered User regular
    
    
    switch (state) {
    	case "IDLE":{
    		image_speed = 0;
    		v_speed = 0;
    		h_speed = 0;
    
    
    
    		if (obj_input.in_up) state = "UP";
    		if (obj_input.in_down) state = "Down";
    		if (obj_input.in_left) state = "Left";
    		if (obj_input.in_right) state = "Right";
    		if (!obj_input.in_up && !obj_input.in_down && !obj_input.in_left && !obj_input.in_right) state = "IDLE";
    			
    		break;
    	}
    	case "UP":{
    		image_speed = anim_speed;
    		sprite_index = spr_player_up_walk;
    		v_speed = -1 * velocity;
    		h_speed = 0;
    
    		if (obj_input.in_up) state = "UP";
    		if (obj_input.in_down) state = "Down";
    		if (obj_input.in_left) state = "Left";
    		if (obj_input.in_right) state = "Right";
    		if (!obj_input.in_up && !obj_input.in_down && !obj_input.in_left && !obj_input.in_right) state = "IDLE";
    
    		
    		break;
    	}
    	case "Down":{
    		image_speed = anim_speed;
    		sprite_index = spr_player_down_walk;
    		v_speed =  velocity;
    		h_speed = 0;
    		
    
    		if (obj_input.in_up) state = "UP";
    		if (obj_input.in_down) state = "Down";
    		if (obj_input.in_left) state = "Left";
    		if (obj_input.in_right) state = "Right";
    		if (!obj_input.in_up && !obj_input.in_down && !obj_input.in_left && !obj_input.in_right) state = "IDLE";
    
    		
    		break;
    	}
    	case "Left":{
    		image_speed = anim_speed;
    		sprite_index = spr_player_side_walk;
    		image_xscale = -1;
    		v_speed = 0;
    		h_speed = -1 * velocity;
    		
    		
    
    		if (obj_input.in_up) state = "UP";
    		if (obj_input.in_down) state = "Down";
    		if (obj_input.in_left) state = "Left";
    		if (obj_input.in_right) state = "Right";
    		if (!obj_input.in_up && !obj_input.in_down && !obj_input.in_left && !obj_input.in_right) state = "IDLE";
    
    		
    		break;
    	}
    	case "Right":{
    		image_speed = anim_speed;
    		sprite_index = spr_player_side_walk;
    		image_xscale = 1;
    		v_speed = 0;
    		h_speed = velocity;
    		
    		scr_obj_player_state_input_ifcheck();
    		if (obj_input.in_up) state = "UP";
    		if (obj_input.in_down) state = "Down";
    		if (obj_input.in_left) state = "Left";
    		if (obj_input.in_right) state = "Right";
    		if (!obj_input.in_up && !obj_input.in_down && !obj_input.in_left && !obj_input.in_right) state = "IDLE";
    		
    
    		
    		break;
    	}	
    }
    
    
    
    y += v_speed;
    x += h_speed;
    
    

    So I'm working through the old tutorial....https://www.youtube.com/watch?v=8OSWIxKPnL4

    I made it farther than this, but now my state machine isn't working.

    Game starts in idle state, and it It works if I comment out every version of "if (!obj_input.in_up && !obj_input.in_down && !obj_input.in_left && !obj_input.in_right) state = "IDLE";" (I know it should be a script) but the moment I leave that line of code everywhere, the player stays in the idle state. But the when I include code to set it to "IDLE" when no movement keys are being pressed, running the game keeps it stuck in the idle state.

  • PeewiPeewi Registered User regular
    
    
    switch (state) {
    	case "IDLE":{
    		image_speed = 0;
    		v_speed = 0;
    		h_speed = 0;
    
    
    
    		if (obj_input.in_up) state = "UP";
    		if (obj_input.in_down) state = "Down";
    		if (obj_input.in_left) state = "Left";
    		if (obj_input.in_right) state = "Right";
    		if (!obj_input.in_up && !obj_input.in_down && !obj_input.in_left && !obj_input.in_right) state = "IDLE";
    			
    		break;
    	}
    	case "UP":{
    		image_speed = anim_speed;
    		sprite_index = spr_player_up_walk;
    		v_speed = -1 * velocity;
    		h_speed = 0;
    
    		if (obj_input.in_up) state = "UP";
    		if (obj_input.in_down) state = "Down";
    		if (obj_input.in_left) state = "Left";
    		if (obj_input.in_right) state = "Right";
    		if (!obj_input.in_up && !obj_input.in_down && !obj_input.in_left && !obj_input.in_right) state = "IDLE";
    
    		
    		break;
    	}
    	case "Down":{
    		image_speed = anim_speed;
    		sprite_index = spr_player_down_walk;
    		v_speed =  velocity;
    		h_speed = 0;
    		
    
    		if (obj_input.in_up) state = "UP";
    		if (obj_input.in_down) state = "Down";
    		if (obj_input.in_left) state = "Left";
    		if (obj_input.in_right) state = "Right";
    		if (!obj_input.in_up && !obj_input.in_down && !obj_input.in_left && !obj_input.in_right) state = "IDLE";
    
    		
    		break;
    	}
    	case "Left":{
    		image_speed = anim_speed;
    		sprite_index = spr_player_side_walk;
    		image_xscale = -1;
    		v_speed = 0;
    		h_speed = -1 * velocity;
    		
    		
    
    		if (obj_input.in_up) state = "UP";
    		if (obj_input.in_down) state = "Down";
    		if (obj_input.in_left) state = "Left";
    		if (obj_input.in_right) state = "Right";
    		if (!obj_input.in_up && !obj_input.in_down && !obj_input.in_left && !obj_input.in_right) state = "IDLE";
    
    		
    		break;
    	}
    	case "Right":{
    		image_speed = anim_speed;
    		sprite_index = spr_player_side_walk;
    		image_xscale = 1;
    		v_speed = 0;
    		h_speed = velocity;
    		
    		scr_obj_player_state_input_ifcheck();
    		if (obj_input.in_up) state = "UP";
    		if (obj_input.in_down) state = "Down";
    		if (obj_input.in_left) state = "Left";
    		if (obj_input.in_right) state = "Right";
    		if (!obj_input.in_up && !obj_input.in_down && !obj_input.in_left && !obj_input.in_right) state = "IDLE";
    		
    
    		
    		break;
    	}	
    }
    
    
    
    y += v_speed;
    x += h_speed;
    
    

    So I'm working through the old tutorial....https://www.youtube.com/watch?v=8OSWIxKPnL4

    I made it farther than this, but now my state machine isn't working.

    Game starts in idle state, and it It works if I comment out every version of "if (!obj_input.in_up && !obj_input.in_down && !obj_input.in_left && !obj_input.in_right) state = "IDLE";" (I know it should be a script) but the moment I leave that line of code everywhere, the player stays in the idle state. But the when I include code to set it to "IDLE" when no movement keys are being pressed, running the game keeps it stuck in the idle state.

    From this bit of code, I don't see why it would be broken in the way you describe. If the movement states work, I'd expect the idle state to also work. Do you change the state anywhere else?

    The tutorial you posted includes an attack state, and your posted code does not. Is that because you haven't implemented it, or have you excluded that from the posted code?

    It sounds like it used to work, but broke at some point. Were you making changes to the section of code you posted or another section?

  • RoyceSraphimRoyceSraphim Registered User regular
    Writing it from scratch, new assets.

    Went through it up to the state machine and that line just stopped it.

    I did this before in gamemaker 1, until life and got further. So i dunno why it doesn't work in this engine

  • PeewiPeewi Registered User regular
    So if you comment out all instances of that line, you can move (but not stop)?

    If yes, the only thing I can come up with is that the input properties aren't returning the same values when checked multiple times. Which I think would be an odd way of designing that.

    If no, there might be something wrong with how you're checking input.

  • RoyceSraphimRoyceSraphim Registered User regular
    edited February 2
    Peewi wrote: »
    So if you comment out all instances of that line, you can move (but not stop)?

    If yes, the only thing I can come up with is that the input properties aren't returning the same values when checked multiple times. Which I think would be an odd way of designing that.

    If no, there might be something wrong with how you're checking input.

    ......i mean I could change direction.....i think.

    edit: I set my state in the creation event as "Idle" and not "IDLE"

    RoyceSraphim on
  • KupiKupi Registered User regular
    Kupi’s Weekly Friday Game Dev Status Report

    Last week I concluded by saying that I’d finally start working on the terrain painter I’ve been talking up for weeks/months. This week I got completely sidetracked by an exercise in curiosity.

    The question I just couldn’t get out of my head was “how many objects can you put into play in Godot before it starts getting framey?” Some of the games I have fantasies of publishing are shmups, and you can always add more bullets. If Godot, by design, doesn’t concern itself with ultra-high object counts, what qualifies as an ultra-high object count?

    This line of investigation is ultimately what led to my post earlier in the week. I built a new test project called “BuggeBox”, involving a 640x480-pixel box of 16x16 brick tiles into which you could throw 100 Bugges at a time (a Bugge being an eight-pixel wide circle collider with a small spider drawn over it). Godot’s rigid body physics exhibited a vexing bug where a collision would be detected with the corner of a tile despite the wall tiles being flush next to one another and therefore technically not even having a corner to hit. I could have simply declared Godot unfit for purpose and moved on, but y’all have been reading my posts for too long now. You know me! I’m stubborn. I will continue to follow an idea long after it’s become obvious to everyone except myself that nothing is going to come of it.

    So I dug around in Godot’s auto-complete for a bit and discovered the Shapecast2D node. Shapecast2D flings the object of your choice toward a target position every physics tick and stores the collisions it discovered. Since mass, inertia, air friction, and so on were never concerns anyway, and the behavior is essentially how body movement is implemented in my engine, this sounded like what I needed. And it was! With just a bit of GDScript I had the bugges bouncing off of the walls in the way they were supposed to.

    Except that sometimes, they’d hit the walls and stick to them. I fought with this for a while, assuming that it was another “stuck in the corner” case; for instance, if the shapecast struck the internal edge of one of the brick tile bodies and reflected its velocity over that surface normal, it would still be traveling into the wall. However, all the breakpointing and debug printing I could throw at it didn’t seem to indicate that any of the “get yourself out of the wall” code I’d included was even going off. And these “stuck in the wall” cases didn’t seem to happen until I had 4,000 bugges in play, so once they appeared it was nearly impossible to examine them in the debugger.

    I got around that problem by rigging up a button to delete any bugge that hadn’t significantly moved from its position on the last physics tick, plus one more. By doing so I could break it down to a single bugge in play and step through its shapecast script. What I discovered is that I was using a function called get_collision_safe_movement_fraction() to determine how much to move the bugge each frame. get_collision_safe_movement_fraction() returns a number from 0 to 1, indicating how far the shape can move without triggering a collision. if the bugge was moving at an extremely shallow angle relative to the surface, it would not actually detect a collision, but also have a safe movement fraction of 0. No movement and no collision to change its velocity equals a stuck bugge. I forced a bare minimum movement per frame and the walls were nicely, consistently rubbery again.

    Using a debug print (to count how many bugges had been created) and Godot’s performance monitor, I created bugges 100 at a time until Godot’s framerate report dropped below 60. The result was about 4500 bugges before it consistently missed frames.

    Then, I went to my own engine and put together an identical scenario. I set up a stopwatch (the C# class) and a counter in the XNA draw method to approximate the number of frames per second, and set up an alert to go off when the frame rate dropped below 60. Dropped in batches of 100 bugges, let it settle for a bit before the next one, and the alert went off at… 4500 bugges.

    Another friend group expressed some surprise that I had not outperformed Godot (and I’m going to be honest, I was more than a little disappointed in myself as well, despite knowing a few of the contributing factors), and suggested that maybe there was an element of GPU bottlenecking at play. So, doing what all honest scientists do, I revised the measure, changing the target from the framerate to the run-time of the physics code itself. Godot provides a monitor for the physics_process() function, where shapecasting and my own script code lives, so I asked: how many bugges can be in play before physics_process() consistently takes 10 ms to run? For Godot, that turned out to 3300 bugges. For a similar measure in my engine (XNA’s Update() method), I was able to put 4000 or so bugges in play before the stopwatch read 10 ms per frame consistently. My conclusion is that there’s some weird scaling issues in play; my engine might be better able to handle large numbers of objects if they stay spread out.

    Regardless, I’m not really interested in interrogating that much further; the salient point is that my engine doesn’t beat Godot by all that much, while boiling the CPU to do it, and requiring my janky WinForms-based editor to put anything together. So while I’ve harped on the terrain painter for a while, for this next week, I’m going to try learning how TileMaps work and implementing my platforming test project in Godot (the one where you pilot Sonic around a bunch of brick half-pipes). If that goes well, I’ll proceed to making an absolute bare-minimum game (as in, a title screen and one level containing no enemies, just some terrain and a goal flag) to see what other Godotisms I run into. Because-- and I realize I’m stating the obvious-- while there are a few things I still prefer about my engine (total control over the codebase, deterministic execution, and amenability to unit testing), using something that people who know what the fuck they’re doing made for the express purpose of making games easier to make is the better road to ever actually publishing something.

    I’ll see you next week. Maybe with something you can actually download and play?? (No.)

    P.S. Here's what a fully-saturated BuggeBox looks like. I feel like one probably doesn't need more than this many objects on-screen to produce meaningful gameplay.
    qzwlxknb8900.png

    My favorite musical instrument is the air-raid siren.
  • PhyphorPhyphor Building Planet Busters Tasting FruitRegistered User regular
    There's no way you are limited to 4500 objects on the GPU side of things, unless they are dispatched individually. Quads of the same object should really get batched and instanced so that should be like 2 draw calls

  • PeewiPeewi Registered User regular
    edit: I set my state in the creation event as "Idle" and not "IDLE"

    That'll do it.

    There are some things you can do to make that type of bug far less likely.

    Option 1:
    Use constants instead of repeating string literals.
    So instead of writing "IDLE" everywhere, you declare your constant at the top of the file, and then use the constant value for the rest of the file.

    Option 2:
    Use enum values instead of strings. Behind the scenes your value will be stored as a number, but you write a name in your code, so it stays easy to read.

    Either option should result in typos being compilation errors, which is easier to fix than something mysteriously not working.

  • ElvenshaeElvenshae Registered User regular
    Yeah, learn to love enums, @RoyceSraphim , because they're a much, much better way to name your states, your colors, your weapon types, your damage types, etc.; they'll enable a useful feature in your rich editor where you can autocomplete your enums, and then never worry about silly typos again. :D

  • KupiKupi Registered User regular
    Kupi's Weekly Friday Game Dev Status Report

    I spent the week working toward implementing my engine's test project in Godot. As of today, I have a level laid out and painted and a Sonic character who absolutely does not move correctly.

    My opinion thus far is divided. Every time I think, this is it, this is the point where Godot completely falls on its face and reveals an architecture-level design decision that I just can't accept, it turns out that yeah, they already thought of it. Like the animation system, which has a sort of Unity-style ability to animate any object property. I thought, boy, as useful as this is, "animation" is a graphical concept. I'll bet you could easily produce bugs by trying to animate some kind of gameplay-related system while the animation system only runs in the idle processing time. But, no! The animation player node has a mode setting for whether you want it to run in the physics or idle process, so if something needs to update on exact frame boundaries, it does! And speaking of exact frame boundaries, I was thinking to myself, gee, it really sucks to have to edit all my durations in terms of seconds, because really want I want is to hold on a particular sprite for three frames before advancing to the next one. Lo and behold, one of the display and snapping options for animations is in terms of frames instead of seconds!

    The bad part is that for an unexpected workflow, it takes a little bit more effort than I'd like to put together sprite animations. Yes, they have an AnimatedSprite2D node, but that works exclusively with sprite sheets of exactly regular size. Most of the characters I design have long, flowing hair and move in all directions, which can spike the height or width of the sprite. Leaving vast areas of transparency in the sprite sheet just to accommodate generating the Godot definition of the animation doesn't feel right, so I've been using the AnimationPlayer to update a Sprite2D with AtlasTextures, and in doing so I found a few nails sticking out of the handles. After a self-inflicted disaster where I wound up editing the RESET animation* instead of the "walking" animation I'd intended to, I decided that instead of defining each AtlasTexture value within the keyframe, I'd pre-define the AtlasTexture values in resource files and only have the keyframe perform the assignment. This meant a lot of going to the file explorer (Godot's, I mean), right-clicking and choosing the Duplicate option, then giving it the name with the next index for the animation I was working on. The problem is, the duplicate was highlighted in the file explorer, but the object inspector was still editing the previous file-- leading to a number of cases where I overwrote the previous sprite with the next sprite's info by mistake. It really feels like when you duplicate an object and the editor highlights it, the duplicate should be the object that you're editing. The same principle applies when I started inserting keyframes into the animation: when you right-click and choose "Insert Keyframe" in the animation editor, the last keyframe stays highlighted and the changes you make apply there. You have to insert a new keyframe, then click it again to highlight it in order to edit the correct value.

    And when I edited the displayed region on the AtlasTextures, the "region editor" always started from the exact center of the (rather extensive) spritesheet I was using. Which meant un-zooming, scrolling to the appropriate area, zooming in again, and only then choosing the new value. I feel like if a region is already set, the region editor should start from the center of the selected region, not the center of the whole image.

    Setting up the tilemap was somewhat easier, though I do see some potential pain points in the future. My test project's terrain tiles all fit in the same amount of space. However, for future projects I'd like to make tiles that, say, have grass sticking off the top. The problem is that, like with AnimatedSprite2D, terrain tiles can only be assigned from an absolutely regular grid. You can set up tile sprites to display offset from center, and with a greater size than the TileMap you're placing them on, but if you do so you have to include the same amount of margin space for all your other tiles. You could also conceivably set up the grass in its own distinct tile, but I'm not sure if you could automatically emit it as part of the terrain system (which automatically modifies tiles based on the tiles they're adjacent to). And if your tile size doesn't match your placement size, the tool that automatically assigns your tile a square-shaped physics volume won't assign it the right size (because your real grid is e.g. 32 pixels, but your tile set has a size of 40 pixels, so it assigns the tile a physics volume of a 40-by-40 square). You could, of course, manually define the physics volume to be the size you want it, but it's not quite as convenient.

    And up to the deadline yesterday, I was working on getting the character motion working. Naturally, there's a purpose-built object type in Godot for 2D character movement, the CharacterBody2D, with built-in move-and-slide behavior very, very similar to what I called "PlatformingBody" in my own engine. Unfortunately, I wasn't able to get it to give me Sonic-like "run up a wall" physics with the out-of-the-box tools, despite it having a configurable "up" vector that ought to indicate which direction the character is pointing. I don't know if that's because the "up" vector is automatically affected by the parent object's rotation and therefore didn't need to be manually assigned to match the floor's surface normal, or if it just doesn't quite work the way I expect it to, but so far the only thing I've seen happen when I try to send Sonic up a half-pipe is he starts break-dancing, clips into the wall, and eventually winds up sliding around on his head. That the movement fails as drastically as it does is honestly kind of impressive. Currently I'm in the process of building out a system using the more manual move-and-collide method and manually tracking if the character is on the ground or can walk up a surface it collides with.

    But, there's one thing that really takes the cake and might just sent me fleeing back to my engine on its own: it's a matter of settled law among the Godot developers that Godot's 2D systems have an inverted y-axis. Positive Y means moving downward on the screen, even in the physics engine. It's... stultifying.

    Nevertheless, I'm determined to at least get the character moving correctly before I commit to either path, so that's what I'm going to be working on for this next week. See you next time!


    * The RESET animation is a design pattern when operating with these sorts of property-tweening animation systems, where every animation transition is actually two steps: playing a 0-duration RESET animation, and then the actual target animation. The RESET animation contains a default value for any property managed by any animation in the set. Doing this helps prevent things like lingering hitboxes, displaced limbs, and other errors that arise from transitioning out of animations unexpectedly and leaving property data in a half-edited state.

    My favorite musical instrument is the air-raid siren.
  • PeewiPeewi Registered User regular
    Kupi wrote: »
    But, there's one thing that really takes the cake and might just sent me fleeing back to my engine on its own: it's a matter of settled law among the Godot developers that Godot's 2D systems have an inverted y-axis. Positive Y means moving downward on the screen, even in the physics engine. It's... stultifying.

    I thought that was fairly common in (2D) game engines?

    Weren't you on Monogame before? Monogame's spritebatch definitely uses top left as the origin and positive Y as down.

  • PhyphorPhyphor Building Planet Busters Tasting FruitRegistered User regular
    edited February 9
    Everybody agrees that the left side of the screen is x=0

    Whether you consider the top-left or bottom-left as y=0 depends on your view
    If you view this as a mathematics quadrant, y=0 is the bottom and +y is up because it's math coordinates
    If you view this as a scan order monitor, y=0 is the top and +y is down because it's pixel coordinates

    Phyphor on
  • PolaritiePolaritie Sleepy Registered User regular
    Yeah, I figured it had to do with how CRTs filled the screen.

    Steam: Polaritie
    3DS: 0473-8507-2652
    Switch: SW-5185-4991-5118
    PSN: AbEntropy
  • RoyceSraphimRoyceSraphim Registered User regular
    Additionally, assets are loaded from that corner as well. At least that was how I was taught in webpage design decades ago.

  • KupiKupi Registered User regular
    MonoGame's SpriteBatch class uses positive Y as down for its Draw() method, sure. I have a conversion that translates from physical coordinates to screen coordinates. But for physics calculations, my engine treats positive Y as up, the way it's supposed to be.

    I'm not aware of many arguments for positive Y being down that aren't based in history and convention specific to computer graphics and, like, document processing. (I am not aware of many things.) Which seems irrelevant to physics simulation, which is what games most frequently are!

    My favorite musical instrument is the air-raid siren.
  • PhyphorPhyphor Building Planet Busters Tasting FruitRegistered User regular
    A physics system arguably shouldn't care about it's coordinate system though, just change the gravity vector

    This disagreement has always existed. Most 3D engines settled on XY is the horizontal plane and +Z is up. But as far as the GPU is concerned, XY is the screen plane and Z is in/out

  • VontreVontre Registered User regular
    Y is up in Unity Engine though. :v

    It's not really standardized at all. Unreal Engine's coordinates are totally fucking wild because it was built for FPS games. Just the most obnoxious shit like X = reverse into the screen or something. Oh well.

  • KupiKupi Registered User regular
    Okay, I found the catastrophic engine-level design error. You can define a collision shape as "one-way", but this is a boolean value. Collision shapes that are one-way are one-way only against things that are moving downward. If a one-way collision shape is rotated, the one-way effect applies in whatever would be upward in the new frame of reference.

    But you can't rotate the tiles in your TileMaps, so TileMap collision shapes can only ever be one-way straight up. This doesn't preclude creating loop-de-loops, but it does make doing so an absolute pain in the ass requiring custom scenes to accomplish.

    Now, it occurs to me that for a platform game, a loop-de-loop really serves no useful purpose except specifically to invoke Sonic the Hedgehog, who did it solely to indicate how terrifically fast he was and flex on Mario's axis-locked motion (at the time). But are you really a proper indie platform game dev if you aren't being unthinkingly* derivative?

    * phone posting means I typed this as "bunthunkingly", which makes almost as much sense in context

    My favorite musical instrument is the air-raid siren.
  • LD50LD50 Registered User regular
    Kupi wrote: »
    Okay, I found the catastrophic engine-level design error. You can define a collision shape as "one-way", but this is a boolean value. Collision shapes that are one-way are one-way only against things that are moving downward. If a one-way collision shape is rotated, the one-way effect applies in whatever would be upward in the new frame of reference.

    But you can't rotate the tiles in your TileMaps, so TileMap collision shapes can only ever be one-way straight up. This doesn't preclude creating loop-de-loops, but it does make doing so an absolute pain in the ass requiring custom scenes to accomplish.

    Now, it occurs to me that for a platform game, a loop-de-loop really serves no useful purpose except specifically to invoke Sonic the Hedgehog, who did it solely to indicate how terrifically fast he was and flex on Mario's axis-locked motion (at the time). But are you really a proper indie platform game dev if you aren't being unthinkingly* derivative?

    * phone posting means I typed this as "bunthunkingly", which makes almost as much sense in context

    I read this as butthunkingly, which makes even more sense (at least to me).

  • GlalGlal AiredaleRegistered User regular
    Kupi wrote: »
    Okay, I found the catastrophic engine-level design error. You can define a collision shape as "one-way", but this is a boolean value. Collision shapes that are one-way are one-way only against things that are moving downward. If a one-way collision shape is rotated, the one-way effect applies in whatever would be upward in the new frame of reference.

    But you can't rotate the tiles in your TileMaps, so TileMap collision shapes can only ever be one-way straight up. This doesn't preclude creating loop-de-loops, but it does make doing so an absolute pain in the ass requiring custom scenes to accomplish.

    Now, it occurs to me that for a platform game, a loop-de-loop really serves no useful purpose except specifically to invoke Sonic the Hedgehog, who did it solely to indicate how terrifically fast he was and flex on Mario's axis-locked motion (at the time). But are you really a proper indie platform game dev if you aren't being unthinkingly* derivative?

    * phone posting means I typed this as "bunthunkingly", which makes almost as much sense in context
    You can always have a second TileMap for the tiles whose "down" you want to be different. Rotate the tilemap itself and stamp away.

  • KupiKupi Registered User regular
    Kupi’s Weekly Friday Game Dev Status Report

    I don’t feel like I did enough this week. I never feel like I did enough any week.

    It’s looking like the Godot pivot is going to stick; as I continued to work on porting my test project over, I continued to discover cases where Godot does the thing I would prefer it to, or accounted for weaknesses I perceived in it. I’m sure as I move into practical applications I’ll bump up against some limit or another, but even then, it’s open-source. I can just build the thing and debug it if I really need to (and building from source code is something I’m going to wind up doing eventually, but we’ll get to that). Miscellaneous assorted things I’ve learned this week follow:

    While scrolling around at the speed of sound in my test project, I found that the tiles in a TileMap were showing some visible tearing at the seams between tiles. You can see it in this video:

    https://youtu.be/E9W58gwpLFY

    Aha, says I, this is where the received wisdom is to attach a script to your camera that rounds it to pixel boundaries, forcing you to remember to do this every time, right? Nope, pixel rounding is built straight into Godot; in Project Settings > Rendering > 2D: Snap 2D Transforms to Pixel, and Snap 2D Vertices to Pixel.

    While on a random trawl through the Godot subreddit, I came across a thread on the topic of performance. This was something I meant to discuss in a previous post, but my train of thought laid its railing around that particular subject. I’ve been working with GDScript because I want to get more experience with languages that aren’t C#, and while I’ve enjoyed how easy it is to use, y’all have read my posts (I assume; you could just be hitting the Awesome button by reflex any time you see a large amount of text but receiving actual replies would seem to give the lie to that theory): I am very, overly, concerned with performance. While reading up on GDScript, I found a page in the documentation that indicated that GDScript’s interpreter is heavily virtualized, which I am Humpty-Dumptying to mean that it can’t assume anything about the variables that you’re working with. If you write something like…
    var x = 5
    var y = 7
    var z = x + y
    

    In order to produce the sum of x and y, it has to go through a giant staircase of possibilities. So long as x is a variant, you might actually have assigned it a custom addition operator, so it looks for that first. Then it looks at y and sees if it has a custom summation operator when it’s on the right side. Then it starts interrogating both variables for their types to see if their types support the operator. That’s… a lot of work to sum two integers. And pretty much every variable access, property access, or function call is like this.

    Now, I was previously aware of type hinting, both in Python and in GDScript (which mimics Python to the best of its ability). You can assign a type to a variable in order to make the interpreter enforce that assignments match the target type, and also activate text-completion features in the editor. But it’s not just for your convenience; with the type hint, the interpreter can also bypass several levels of that virtual method staircase. According to this blog post on the subject, a tight loop of repeated integer summation and assignment ran in 25-30% less time with type hints rather than without them.

    So that’s great and all, but it requires a level of discipline out of you to get that benefit, right? Well, yet again… Godot has a setting for that. In Project Settings > Debug > GDScript, you can control which events and code structures send messages to the debug environment, and one of them is “Untyped Declaration”. You can set that to Error to force the environment to force you to include types in all of your variable and function declarations. To save yourself keystrokes, you can set the editor setting text_editor/completion/add_type_hints to auto-fill types when, say, overriding known functions. And finally, if typing out the name of a type for a variable is too many keystrokes, there’s an “type inferencing assignment operator”. These two lines mean the same thing:
    var x:int = 5
    var x := 5
    

    In the second case, the variable takes on the type of the object you’re assigning to it.

    Since I mentioned building Godot from the source code before, I suppose I better pay off on that foreshadowing. I was looking into the export process and discovered 1) something disappointing, followed by 2) the fact that it had been accounted for. Who’d have guessed? So, when you export a Godot project, the output is two things: one, a (slightly modified?) version of the Godot editor executable containing only the engine code, and two, a packed version of all your content files. By default, it’s a PCK file, which is just all your raw content files stapled together in one contiguous data blob. I believe this means that Godot’s file-loading system just holds one file handle open and handles all loading by seeking to the appropriate location and pulling the data out. I’m not sure if modern hard drives actually support what I’m going to reflexively call multi-threaded loading (servicing multiple requests at the same time rather than dealing with them in serial), but since you can send file loads to a background thread it doesn’t really make much difference to me. No, the disappointing thing was that, seriously, all your content files are just deployed raw. That includes your game code in any of your GDScript files! With the comments, even! You can just right-click the PCK, click “Open in Notepad”, and there’s your game’s source code out in the open.

    … and this is accounted for. Though it requires you to build the engine yourself, there’s a known path for embedding an SHA-256 encryption key in your executable, providing that encryption key to the export template, and thereby deploying the game content in encrypted format (which is then decrypted at run-time). Now, naturally, someone could reach into your executable, pull the encryption key, and decrypt your content files, but the idea isn’t to make the data completely inaccessible— just to make it a little more secure than “provided in plain text”.

    And finally, I decided to experiment with oversize tiles in TileSets— ones where, say, the placement grid is 32 pixels across, but the actual tiles are 36 pixels across so that grass can extend into the next tile. Originally, my concern was that this would complicate defining the physics volumes for these tiles. As it turns out, though the editor for collision volumes is in the TileSet editor, and the size per tile is associated with the TileSet, the physics editor pulls the size of the tile from the current TileMap, meaning the one-button “just throw a square down” button creates a volume of the right size.

    And then, with all the serious work complete, I added a few extra little bonuses like scaling Sonic’s walk animation speed as his velocity goes up and fixing his rotation so it always takes the shortest path to the target rotation. The current state of my test project is demonstrated below:

    https://youtu.be/sHHG7pjNPgE

    On an engine-knowledge level, the next thing I want to explore is overall game statement management and level/scene transition. In terms of non-programming goals, I’m at the same position I’ve been for a while: make some actual art assets. Some original sprites, perhaps? Music? Sound effects? Anything?!

    Until next week.

    My favorite musical instrument is the air-raid siren.
  • KupiKupi Registered User regular
    Kupi's Weekly Friday Game Dev Status Report

    On Saturday, I spoke with a close friend of many years to ask them if they'd mind helping keep me accountable for progressing in my game dev work. While my posts are frequently long and drift between topics, the fact is I can turn something that took me all of a couple hours to do and make it look like it took the whole week. So long as I'm trying to reach a target of something like even part-time work (I'm presently unemployed so it's not as though I'm trying to force more work out of myself than my time can support), I need to be doing more on any given day. And I was never more productive than I was at the job where I (voluntarily!) sent my boss a daily report of what I'd done at the end of each day-- because I knew he'd notice if I didn't, which meant I had to have something to report. My friend agreed, with the sole concern that as someone with ADHD they might take a bit to manage to remember to ask for the report. Which is fine, because... well, you can look at my record with this thread. I don't miss my weeklies (generally speaking). I could hit the dailies long enough for them to acclimate to the routine.

    On Monday, I woke up with a sore throat at 5 AM. By 7 that evening, I had some throbbing in my head, chills, and aches in my calf muscles. I used one of my expired-but-good-enough-for-the-government at-home Covid tests, and the result was "very covid".

    Consequently, I have spent the week doing nothing but watching vapid streams on Twitch and trying to avoid all forms of physical and mental stress. I seem to be past the acute phase of the disease but still very much in the "lingering crapfeel" phase. If I make anything, I'll let you know. If not, there won't be a post.

    My favorite musical instrument is the air-raid siren.
  • RoyceSraphimRoyceSraphim Registered User regular
    https://youtube.com/GN2f9R3jNaE?si=JvgLbRW3LoFGo2gQ


    I dunno who needs this or what seed this will plant in your minds but the concave eye effect is a tool for game design

  • RoyceSraphimRoyceSraphim Registered User regular
    Yay, another thing I did right the last time but didn't work this time.

    Running this tutorial, in which, yay, I did learn about enums!
    https://www.youtube.com/watch?v=Kxa0myAn2U8&list=PLsLwv4RXTczJyMxB8znlQkW7H3kEYfYQ6&index=6

    So i get the following error
    
    ___________________________________________
    ############################################################################################
    ERROR in
    action number 1
    of  Step Event0
    for object obj_player:
    
    Variable obj_player.arguement(100004, 0) not set before reading it.
     at gml_Script_scr_check_collision_obj (line 7) -        _vx = arguement[0];
    ############################################################################################
    gml_Script_scr_check_collision_obj (line 7)
    gml_Object_obj_player_Step_0 (line 184) - scr_check_collision_obj(h_speed, v_speed, obj_solid);
    
    




    My script is the following
    // Script assets have changed for v2.3.0 see
    // https://help.yoyogames.com/hc/en-us/articles/360005277377 for more information
    function scr_check_collision_obj(){
    	
    	var _vx, _vy, _collision;
    	
    	_vx = arguement[0];
    	_vy = arguement[1];
    	_collision = false;
    	
    	
    	repeat ( max(abs(_vx), abs(_vy))){
    		for (var _i = 2; _i < arguement_count; _i++){
    			if ( place_meeting( x + sign(_vx), y + sign(_vy), arguement[_i]) ) {
    				_collision = true;
    				break;
    			}	
    		}
    		
    		if (!_collision) {
    			x += sign(_vx);
    			y += sign(_vy);			
    		} else {
    			break;
    		}
    	
    	
    
    	}
    	return _collision;
    }
    

    Funny thing I think points to the problem is the following error showing up in the player script where the movement is done.
    The script function 'scr_check_collision_obj' takes no more than 0 arguements but 3 are provided.
    

  • PeewiPeewi Registered User regular
    You spelled argument wrong.

    I'm not watching that entire tutorial, but I looked at it briefly. The code shown in the tutorial does not include a function declaration in the shown script file, but yours does. I don't know Game Maker specifically, but I would assume that would change how to call the code.

  • RoyceSraphimRoyceSraphim Registered User regular
    Its the new way to do it in gamemaker studio 2

  • Dr. ChaosDr. Chaos Post nuclear nuisance Registered User regular
    edited March 1
    Man, I love working with 8-bit resources. They're just so comfy.

    Dr. Chaos on
    Pokemon GO: 7113 6338 6875/ FF14: Buckle Landrunner /Steam Profile
  • KupiKupi Registered User regular
    Kupi's Weekly Friday Game Dev Status Report

    I'm still in the recovery phase of Covid (the one that ends, not the part where you suffer a permanent reduction in cardiovascular capacity for the rest of your life), so I didn't do much this week. But I twiddled, and I report my game dev activities on Friday, so a documentation of twiddling you shall receive.

    One of my ideas for the Sonic-like game is a damage system where, instead of dropping all of your ring-equivalent items the moment you take damage, instead what happens is the game freezes in place, applies a distortion filter to the music, and you can press the game's all-purpose "do something other than jump" button to dodge out of the way. You lose "rings" for every X units of time that passes in this frozen state, so with good reaction time and a sense of when you're about to get hit, you can reduce the amount of "damage" you take from any given hit, to the point of being able to tank any and all damage if you time it frame-perfectly. Godot has the ability to pitch-shift sound files as you play them, so I experimented with a script that would wobble the pitch in various ways. I did not find anything that sounded exactly right.

    I did some diving in the manuals on a topic of interest, since perf is always in the back of my mind. Specifically what I looked into is the "server" architecture that sits behind the node architecture. Essentially, all the major subsystems that power a game-- physics, rendering, audio, and a few others-- are handled in Godot by a "server". Essentially, it's the code responsible for handling whatever the subsystem is interested in; the physics server holds all the physics-related code and updates things. Servers tend to run on their own threads, quietly updating what they can between callbacks that you've established into your own scripts. Most of the physics-related nodes are implemented as a wrapper around something managed by the physics server-- Area2D, for instance, creates a physics entity in the 2D physics engine whose type is Area. RigidBody creates the same type of physics entity, but with its type set to RigidBody, and so on. Where doing this causes you to lose performance is that the node sets up callbacks in the physics engine to mirror updates to e.g. the entity's position into the node's transform, and vice-versa. The engine spends a lot of effort keeping two different objects synchronized. However, there's an interface into every server that lets you declare and update the entities it controls. If you have a whole lot of objects that are very similar and relatively simple, you get a big perf boost by independently creating the entities and just tracking and updating themselves instead of using nodes.

    And finally, I did some doodling in Asesprite. Right now the idea I have in my head is that I'm going to make a simpler Mario-like platformer, just to have the experience of taking a game soup to nuts before I work on more ambitious projects (while still having a large / narrative-driven enough scope that I actually feel like I want to work on it). I took an initial crack at the proportions that didn't work out, then consulted a Mario 3 spritesheet to see what I could absorb of the style and tried again. After that, I tried giving the limbs a bit more roundness and updated the outlines to match the fill colors that they surrounded.

    hpk6r3q9jgsg.png

    I can promise no more than further twiddling for the coming week.

    My favorite musical instrument is the air-raid siren.
  • Dr. ChaosDr. Chaos Post nuclear nuisance Registered User regular
    edited March 10
    Its a self imposed map making training week for me.

    Must..not...make...everthing...a box.

    Dr. Chaos on
    Pokemon GO: 7113 6338 6875/ FF14: Buckle Landrunner /Steam Profile
  • IanatorIanator Gaze upon my works, ye mighty and facepalm.Registered User regular
    Here am I, whose head is now filled with images in motion that can best be described as "Animal Crossing, in SPACE!". And little by little those images are making their way to paper, that I may someday share the experience with others.

    ...Anyways, guess I'm learning Blender and Unreal today!

    steam_sig.png
    Twitch | Blizzard: Ianator#1479 | 3DS: Ianator - 1779 2336 5317 | FFXIV: Iana Ateliere (NA Sarg)
    Backlog Challenge List
  • KupiKupi Registered User regular
    Kupi's Weekly Friday Game Dev Status Report

    This week I read the Balatro dev's AMA, in which they mentioned that a key to their success was a variation on Stephen King's maxim, saying that they enjoyed the actual making of the game rather than just wanting to have made a game. I thought about how I have to employ all kinds of productivity/discipline measures (like this weekly report!) to keep myself on track because on a micro level apparently I'd rather not be doing the actual difficult work of building a game, and spent the rest of the day staring off into space.

    I watched Sakurai's video on "competition and abundance", where he said that if you don't feel like keeping up, it's okay to give up because there are so many people who actually want to make games that nobody will notice the difference.

    I read a post elsewhere mocking a dev who was throwing a fit on Twitter about how it didn't matter if their game crashed when you unplugged the controller because players shouldn't be doing that anyway, and the conversation segued into how their game sort of looked like every other pixel-art platform game made in a commercial engine, and gee, why do devs bother anyway, since they all look and play like crap anyway. And I thought about how in my last post I said I was working on a pixel-art platform game in an open-source engine that I don't really expect to go anywhere.

    I've been thinking a lot lately about how everything I've created in a professional context has been destroyed by a man in an expensive suit to raise profit margins. And how the most proximate cause of my recent covid infection is the volunteer work I did. And how pretty much the only thing I've ever said I really actually wanted to do was make video games. And just noting how the math on all that works out.

    And I also toyed around with a damage-scaling function for an RPG with properties that I liked. I think I've presented something similar before, so I won't bore you with the details.

    My favorite musical instrument is the air-raid siren.
Sign In or Register to comment.