Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411474 Posts in 69369 Topics- by 58423 Members - Latest Member: antkind

April 23, 2024, 01:25:16 PM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsCommunityDevLogsLeilani's Island
Pages: 1 ... 52 53 [54] 55 56 ... 67
Print
Author Topic: Leilani's Island  (Read 411429 times)
DrDerekDoctors
THE ARSEHAMMER
Level 8
******



View Profile WWW
« Reply #1060 on: January 19, 2020, 11:47:47 PM »



This is done by running the normal gameplay but with a recorded set of inputs. The game runs at the same framerate as the recording was made at so it (hopefully) doesn't de-sync.

I do this in my engine for debugging things! Although despite rolling my own random number generator, it still manages to de-sync which is really bloomin' annoying. Tongue I hope you have better luck with yours staying in sync!
Logged

Me, David Williamson and Mark Foster do an Indie Games podcast. Give it a listen. And then I'll send you an apology.
http://pigignorant.com/
JobLeonard
Level 10
*****



View Profile
« Reply #1061 on: January 20, 2020, 01:50:17 AM »

I do this in my engine for debugging things!
I don't even develop games and I have some version of it - the previous web-app I built had a Google Maps like function where it saved all app state in a compressed URL, which let people instantly re-open or share a session with others.

I ended up with a ton of bookmarks for edge-cases that broke the app for quick checking Wink
Logged
Ishi
Pixelhead
Level 10
******


coffee&coding


View Profile WWW
« Reply #1062 on: January 20, 2020, 09:32:18 AM »

I do this in my engine for debugging things!
I don't even develop games and I have some version of it - the previous web-app I built had a Google Maps like function where it saved all app state in a compressed URL, which let people instantly re-open or share a session with others.

I ended up with a ton of bookmarks for edge-cases that broke the app for quick checking Wink

I do also use the input recording feature for debugging! It's so handy when something is difficult to reproduce; also the fact that I can set breakpoints to investigate what's happening which would normally prevent me from doing the controller inputs required to actually make the bug happen. It sounds like the website version is super useful too.

Additionally I use the same recordings as playtesting logs, so playtesters can send me the logs and I can literally watch the whole session. I do get some occasional desyncing issues here - I'm not sure where they come from, the same recording will have consistent desyncing each time it's played back, but I don't know if it's being recorded badly or played back badly. But it's not a player-facing feature so as long as the recordings I use for the attract mode work, it's good enough Smiley

The recordings contain regular reports of the player's position, which I use to display a 'desync' warning on screen if it doesn't match the player's position in the simulation, so at least I don't have to try and guess whether it's playing back correctly or not.

Other quality of life features include it being easy to play the recording - I just drag and drop the file into the game window and it loads into the appropriate level and starts playback. I have a fast forward button that speeds up everything, which is a general feature that also applies to normal gameplay for quick debugging and things. There's also a 'rewind' button that displays a black screen while it restarts the recording and simulates everything as fast as possible until it's 6 seconds away from where you were. If you're not too far into the recording it works really well as a quick jump-back-and-watch-that-again button.
Logged

DrDerekDoctors
THE ARSEHAMMER
Level 8
******



View Profile WWW
« Reply #1063 on: January 22, 2020, 07:05:52 AM »

Ooh, adding the position to the data seems a nice idea to check for where stuff de-syncs! I literally just record which frame a button changes state into a CSV file, so a 5 minute recording of gameplay is like 14K, but I'd happily bulk it out with that kinda' information. Smiley
Logged

Me, David Williamson and Mark Foster do an Indie Games podcast. Give it a listen. And then I'll send you an apology.
http://pigignorant.com/
Ishi
Pixelhead
Level 10
******


coffee&coding


View Profile WWW
« Reply #1064 on: January 24, 2020, 06:44:19 PM »

Ongoing Polish

My recent medium-term focus has been working towards a new build that I can send to playtesters. The last one was in October 2018 so it's been a while! There are still some big things left to cover - I'd like to add one more level to the game before then, and the game's sound effects are in dire need of some attention. But I've been working through a huge list of smaller to-do-list items to polish the game up. I'll cover some of them here to give an idea of the kind of tweaks I'm making.

Intro cutscene tidy up

An intro cutscene at the start of the first level has been in the game for ages. It's mostly intended as placeholder, but for now it provides at least a little context to kick the game off with.


(Old version)

When I first added the cutscene it was hacked in with the tools I had available at the time.



The big line running through the scene here is a sequence that I was using to make entities appear at the right time and trigger various other things. I set up each point of the sequence with a 0.6 second delay - and if I wanted a longer delay between the events I would just put lots of extra points on the sequence line! You don't really have to understand this system to see that it's messy.

What's worse is how I prevented the cutscene from being played again if the player died and restarted the level. I actually had two separate copies of this starting area - one with the cutscene and one without. A checkpoint was triggered when starting the level which, if you died, put you into the second version of the area. It worked ok but it makes it twice as much work to change any of the layout of the area!

Now I'm making use of my scripting system to run the cutscene, the same as the boss intro cutscenes. It tells the player which anims to play, makes the crates appear, etc. It's much neater, and easier to edit! Also now there's only one version of this intro area, and the script can be smart about either doing the cutscene stuff, or not, as appropriate.


(New version)

Big Block effects

I don't know if I've shown these big blocks before. But anyway, I haven't made as much use of them as I'd like so I'm trying one out in the intro area.



It needs to be hit multiple times to get the powerup out of it. Previously there were no effects for this - so now it's more satisfying to hit.

Exclamation Block effects

This is another type of block that's been in the game basically forever but I haven't used too much in levels, which I intend to change. When a normal block is hit, the hit continues in a chain reaction to the other side. The exclamation mark block is different in that it continues the chain reaction on all four sides.

The effects for this were really lacklustre before, and it was also hard to follow. I've improved the effects and added a delay.


(Old version)


(New version)

Added slopes throughout the game

Following on from the recent addition of slopes to the game, I've done a pass through nearly every level, adding slopes to the tilesets and then sprinkling them throughout the levels where it feels appropriate.



Shiny Shells

Shells in dark lighting used to look a bit dull.


(Old version)

Now the shine on them isn't affected by lighting, so they stand out nicely!


(New version)

This actually makes use of the composite sprites feature that I added recently. The shell animation is now made of two layers, one of which (the shiny overlay) is not affected by the colour tint of the lighting. No code needed! Smiley

Alert states

Some enemies have visible alert states to show that they're currently reacting to Leilani's presence. I realised I'd forgotten to add it to one type of enemy - these digging machines.



So they now have nice red eyes when they're activated. They also now turn off when they get stuck, as it looked strange for them to remain 'alert' when they were trapped in a space.

Mouse wheel scrolling

As mentioned here, a couple of the game's menus feature scrolling. You can now scroll using the mouse wheel!



More boss polish

The game's current two boss fights have been given a little more attention and improved some more. You can't underestimate how much polish a boss fight needs! Changes range from tweaking boss intro cutscene animations, to tweaking behaviour during the fight, and just tightening up timing to help the fights flow smoothly.

Auto-grab instead of Hold-to-grab

Leilani can grab objects and enemies. The first implementation of this used a 'Grab' input that you had to hold in order to pick up objects. This can be thought of as the Mario method, where holding the run buttons allows picking up some objects. Letting go of the button would make Leilani kick the object (or drop it if holding the down direction).

I've now changed it so Leilani grabs objects automatically. There's now a 'Kick' input which kicks the object when it's pressed. This can be thought of as the Wario method! In those games Wario tends to pick objects up automatically.

I actually like both styles of input in different ways. Having a 'Grab' input makes sense in that while you hold the button, Leilani holds the object - so there's a logical correlation there. On the other hand, kicking the object is a powerful interaction, and it doesn't quite feel right for that to be instigated by letting go of a button. Tapping the 'Kick' button to do the kick makes the kick feel more active.

For now I'm keeping the inputs simpler by going for the 'Kick' button with automatic grabbing. The player already holds the 'Roll' button quite a lot of the time, and it feels a little awkward to start factoring in another button that you have to hold instead (especially when playing on keyboard). Tapping a 'Kick' button now and then feels like it requires much less dexterity.



Watching this gif, when Leilani catches the enemy in mid air, the moment feels a bit flat - it could do with a bit more 'bounce' or some kind of effect. Something else for the to-do list Coffee
Logged

JobLeonard
Level 10
*****



View Profile
« Reply #1065 on: January 25, 2020, 01:43:30 AM »



Watching this gif, when Leilani catches the enemy in mid air, the moment feels a bit flat - it could do with a bit more 'bounce' or some kind of effect. Something else for the to-do list Coffee
You could make her put her arm behind her head in anticipation as the enemy comes within two, three pixels of being grabbed (also would signal to the player that she's about to grab it), and make it aggressively SNAP towards the enemy when she actually grabs it.
Logged
mindless
Level 0
**


View Profile
« Reply #1066 on: January 26, 2020, 06:24:40 AM »

Quote
Watching this gif, when Leilani catches the enemy in mid air, the moment feels a bit flat - it could do with a bit more 'bounce' or some kind of effect.

I believe it looks flat because the object eases into position when caught. Nothing slows down when you go to catch it. Think of a baseball being caught in a glove - there’s a definite snap into the glove as the baseball velocity suddenly just stops.

I think the fix here could be as simple as just stopping the object abruptly when it’s caught as opposed to smoothly easing it into position, even if that means the object jumps a few pixels so it will be in the correct position.
Logged
qMopey
Level 6
*


View Profile WWW
« Reply #1067 on: January 26, 2020, 02:23:14 PM »

I can confirm that snapping is typically better feeling. Here's an example of little men placing logs onto a construction site from a game I was making a while ago. The "snap" was implemented instead of a lerp, since it was simpler and felt better. The snap feels "real", like it really lodged into the right spot suddenly.

Logged
Ishi
Pixelhead
Level 10
******


coffee&coding


View Profile WWW
« Reply #1068 on: January 26, 2020, 07:08:08 PM »

Some good suggestions here, thanks!

The smooth lerp works well when Leilani is picking up an object off the floor but you're right, does look bad when catching something from above. I've had a quick go at a snap & bounce for this situation.



You could make her put her arm behind her head in anticipation as the enemy comes within two, three pixels of being grabbed (also would signal to the player that she's about to grab it), and make it aggressively SNAP towards the enemy when she actually grabs it.

This is an interesting idea, I'll keep it in mind as I play the game more and think about how the grabbing feels. These kind of contextual character reactions can be quite cool. I think Donkey Kong Country Tropical Freeze does this kind of thing where, if you're holding the climb button, DK will reach out for nearby vines and things like that.

edit; fixed the img tags
« Last Edit: January 28, 2020, 06:31:56 PM by Ishi » Logged

mindless
Level 0
**


View Profile
« Reply #1069 on: January 27, 2020, 05:12:55 AM »

The GIF isn’t showing up in the post, but I looked at it using the link. The smooth easing still looks great for picking up the object, and the quick snap looks MUCH better for catching it. The snap also somehow makes Leilani look even cooler!
Logged
JobLeonard
Level 10
*****



View Profile
« Reply #1070 on: January 27, 2020, 06:11:12 AM »

That slow-mo crank Kiss
« Last Edit: January 31, 2020, 07:43:22 AM by JobLeonard » Logged
fall_ark
Level 2
**



View Profile
« Reply #1071 on: January 27, 2020, 09:47:01 AM »

I feel like the catch animation could use maybe 1 extra frame of Leilani raising her arm, between the standing hand position and the current raised position.

On Exclamation Block effects: although there are very good reasons for it, it still feels kinda weird to see shells bounced out sideways from the blocks. Maybe it's because the blocks itself are all facing the same way (upwards) and it just doesn't feel right when the same looking blocks have different effects to them.
Logged

Chinese localizer and influencer. Translated Dead Cells, Slay the Spire, The Count Lucanor, Katana Zero, Dicey Dungeons, and involved in the localization of Reigns, The Curious Expedition, Desktop Dungeons, etc.
If you have questions about Chinese loc and publishing etc., find me at Twitter @SoM_lo
qMopey
Level 6
*


View Profile WWW
« Reply #1072 on: January 27, 2020, 12:52:36 PM »

Looks really good!
Logged
Ishi
Pixelhead
Level 10
******


coffee&coding


View Profile WWW
« Reply #1073 on: January 29, 2020, 05:18:34 PM »

The GIF isn’t showing up in the post

My bad, fixed now Smiley

I feel like the catch animation could use maybe 1 extra frame of Leilani raising her arm, between the standing hand position and the current raised position.

I feel like that would take away from the nice snappiness of the new anim.

On Exclamation Block effects: although there are very good reasons for it, it still feels kinda weird to see shells bounced out sideways from the blocks. Maybe it's because the blocks itself are all facing the same way (upwards) and it just doesn't feel right when the same looking blocks have different effects to them.

Yeah, the main reason is that when solid things come out of blocks (like powerups) they will normally come out on the opposite side from where you hit the block. Otherwise if there's something in the way, it'll choose another direction based on some sort of priority rules. This is dynamic depending on the situation (e.g. if breakable blocks nearby have been destroyed or not). The pre-collected shells that come out of the blocks aren't really solid but follow the same rules for consistency, and also because in a chain of blocks it looks messy if the shells that pop out overlap the blocks that are next in the chain.

Due to the dynamic nature of it, giving the blocks a different look for each direction wouldn't really work. Hopefully it's just a rule of the game that becomes natural over the course of play. Coffee
Logged

mindless
Level 0
**


View Profile
« Reply #1074 on: January 31, 2020, 07:26:13 AM »

The catch sequence is looking really good now! I love how Leilani’s arm lowers slightly from the weight of the object when caught.
Logged
Schoq
Level 10
*****


♡∞


View Profile WWW
« Reply #1075 on: January 31, 2020, 09:18:23 AM »

I'm a bit amazed by how the catching animation looks kinda janky in slomo but perfect in real time
Logged

♡ ♥ make games, not money ♥ ♡
JobLeonard
Level 10
*****



View Profile
« Reply #1076 on: January 31, 2020, 02:58:22 PM »

It's like our brains do the required tweening
Logged
Ishi
Pixelhead
Level 10
******


coffee&coding


View Profile WWW
« Reply #1077 on: January 31, 2020, 03:13:54 PM »

I always say that game dev taught me how long a tenth of a second is, and how much you can do in that time! Which incidentally is the exact length of the pick up / grab animations Grin
Logged

Ishi
Pixelhead
Level 10
******


coffee&coding


View Profile WWW
« Reply #1078 on: February 01, 2020, 09:05:20 PM »

Optimisation

Polish work continues, this week focused on a bit of optimisation. There were a couple of levels that were running badly and I wanted to smooth them out.

The Debug build of the game notably ran very badly in these areas, and still does! I was hoping to get it running nicely but it's not very important. The more optimised Release and Final builds are running nicely which is the important thing.

(For those not familiar with these terms - I'm not sure if other game making tools have the same concept: Debug, Release and Final are common names for different builds made with different compiler settings. Final builds are the ones released to players, and the compiler optimises it to run as quickly as possible. The Debug build is a lot slower, but contains debug information that allows breakpoints to be used, stepping through the code line by line, looking at variable values, etc. The Release build is somewhere in between.)

Mine collision

The first problem area was the challenge level with updrafts and mines.



The large object count - especially with them all in close proximity - was making the game slow down. My collision routines are not the most efficient and usually rely on there not being too much happening! I took a very targeted approach to fix this particular case by giving the mines here a special setting that turns off a lot of their movement code. The mines don't move anyway - but normally could be triggered to explode if a platform moved into them, for example. This isn't possible in this area so it's an easy fix to just not use any of the solid collision code. It now runs at the target frame rate (60fps on my laptop, 120fps on my PC).

Waterfall sprites

The second problem area was some busier parts of the waterfall level.



This was more of a rendering issue. The primary culprit was the glow effect that I put on the edges of the waterfall to make it stand out in the dark lighting.

A brief overview of how my rendering works - I have a Sprite Batch system that I feed sprites into. It does very simple batching on them where possible - consecutive sprites that use the same texture, blend mode, etc, are batched into a single draw call.

The waterfall is composed of lots of sprites 16 pixels in height. The glow effect is done by drawing each sprite twice - once normally, and then once with an additive blend mode to brighten it. This resulted in every sprite having a separate draw call - because there's a normal sprite, then an additive sprite, then a normal sprite, then additive, and they can't be batched together. The fix was to separate these sprites out so all the normal sprites were drawn together, then all the additive sprites, so they batched up nicely.

Sprite ordering

In the process of doing this I overhauled the rather inefficient way that sprites are sorted into layers. For example, the player being always drawn in front of a checkpoint marker.

The game has a concept of Render Priority values, and each sprite is assigned one of these values. The checkpoint uses ENTITY_NORMAL priority and the player uses ENTITY_PLAYER priority, which is higher.

The old process was super slow-

  • Loop through every sprite of every entity, only sprites that have priority ENTITY_NORMAL are put into the sprite batch.
  • Loop through every sprite of every entity, only sprites that have priority ENTITY_PLAYER are put into the sprite batch.
  • Sprite Batch draws all sprites in the order they were added.

Imagine this but for many entities at once, and many different priority levels! And not only entities either - particles, scenery tiles and various other things all fitted into this system in a similar way. Absolutely everything had to be drawn in the order that it should be displayed on screen.

The Leilani code originally used one of my Ludum Dare games as a base. So it does have some of these kind of antiquated systems that were suitable for a small game but not for something more complex!

I've now reworked the Sprite Batch system so we can define a number of groups beforehand - in this case one for each of the Render Priority values. Sprites can be drawn into any of the groups. The sprites within each group will be batched together where possible, and once everything's done, each of the groups will be drawn in the appropriate order. This allows us to loop through the entities just once, and send every sprite into its appropriate group.

  • Loop through every sprite of every entity. All sprites are put into the sprite batch, into the ENTITY_NORMAL or ENTITY_PLAYER group.
  • Sprite Batch draws all ENTITY_NORMAL sprites, then all ENTITY_PLAYER sprites.

This is now much nicer, and a little more efficient!
Logged

JobLeonard
Level 10
*****



View Profile
« Reply #1079 on: February 02, 2020, 04:51:54 PM »

Optimisation

Polish work continues, this week focused on a bit of optimisation. There were a couple of levels that were running badly and I wanted to smooth them out.

The Debug build of the game notably ran very badly in these areas, and still does! I was hoping to get it running nicely but it's not very important. The more optimised Release and Final builds are running nicely which is the important thing.

(For those not familiar with these terms - I'm not sure if other game making tools have the same concept: Debug, Release and Final are common names for different builds made with different compiler settings. Final builds are the ones released to players, and the compiler optimises it to run as quickly as possible. The Debug build is a lot slower, but contains debug information that allows breakpoints to be used, stepping through the code line by line, looking at variable values, etc. The Release build is somewhere in between.)

Mine collision

The first problem area was the challenge level with updrafts and mines.



The large object count - especially with them all in close proximity - was making the game slow down. My collision routines are not the most efficient and usually rely on there not being too much happening! I took a very targeted approach to fix this particular case by giving the mines here a special setting that turns off a lot of their movement code. The mines don't move anyway - but normally could be triggered to explode if a platform moved into them, for example. This isn't possible in this area so it's an easy fix to just not use any of the solid collision code. It now runs at the target frame rate (60fps on my laptop, 120fps on my PC).

Waterfall sprites

The second problem area was some busier parts of the waterfall level.



This was more of a rendering issue. The primary culprit was the glow effect that I put on the edges of the waterfall to make it stand out in the dark lighting.

A brief overview of how my rendering works - I have a Sprite Batch system that I feed sprites into. It does very simple batching on them where possible - consecutive sprites that use the same texture, blend mode, etc, are batched into a single draw call.

The waterfall is composed of lots of sprites 16 pixels in height. The glow effect is done by drawing each sprite twice - once normally, and then once with an additive blend mode to brighten it. This resulted in every sprite having a separate draw call - because there's a normal sprite, then an additive sprite, then a normal sprite, then additive, and they can't be batched together. The fix was to separate these sprites out so all the normal sprites were drawn together, then all the additive sprites, so they batched up nicely.

Sprite ordering

In the process of doing this I overhauled the rather inefficient way that sprites are sorted into layers. For example, the player being always drawn in front of a checkpoint marker.

The game has a concept of Render Priority values, and each sprite is assigned one of these values. The checkpoint uses ENTITY_NORMAL priority and the player uses ENTITY_PLAYER priority, which is higher.

The old process was super slow-

  • Loop through every sprite of every entity, only sprites that have priority ENTITY_NORMAL are put into the sprite batch.
  • Loop through every sprite of every entity, only sprites that have priority ENTITY_PLAYER are put into the sprite batch.
  • Sprite Batch draws all sprites in the order they were added.

Imagine this but for many entities at once, and many different priority levels! And not only entities either - particles, scenery tiles and various other things all fitted into this system in a similar way. Absolutely everything had to be drawn in the order that it should be displayed on screen.

The Leilani code originally used one of my Ludum Dare games as a base. So it does have some of these kind of antiquated systems that were suitable for a small game but not for something more complex!

I've now reworked the Sprite Batch system so we can define a number of groups beforehand - in this case one for each of the Render Priority values. Sprites can be drawn into any of the groups. The sprites within each group will be batched together where possible, and once everything's done, each of the groups will be drawn in the appropriate order. This allows us to loop through the entities just once, and send every sprite into its appropriate group.

  • Loop through every sprite of every entity. All sprites are put into the sprite batch, into the ENTITY_NORMAL or ENTITY_PLAYER group.
  • Sprite Batch draws all ENTITY_NORMAL sprites, then all ENTITY_PLAYER sprites.

This is now much nicer, and a little more efficient!

Quote
My collision routines are not the most efficient and usually rely on there not being too much happening!

Although you're probably happy with your current collision routines, I have to put an obligatory link to the rbush and flatbush libraries, which obviously are the wrong language for your usecase (JavaScript) but might have some algorithmic interest - near the end of the readme of rbush there are a few links to papers about r-trees and their derivatives as well:

https://github.com/mourner/rbush

https://github.com/mourner/flatbush/blob/master/index.js
Logged
Pages: 1 ... 52 53 [54] 55 56 ... 67
Print
Jump to:  

Theme orange-lt created by panic