[Super Dungeon Smashers][Roguelite][Devlog](pre-alpha)

F

Felipe Rybakovas

Guest
Sure, but it's probably less cool than I made it sound. ;)
Technically there are 2 (pretty different) animation systems; the one for the Player, which is all about messing around with sprite offsets and rotation, mostly based on movement and mouse position.

Gonna spoiler the rest because it's big-ish.
As for the code that animates the player sprites, It's mostly a lot of stuff like this:

Code:
// (adding some extra comments so you know what does what)
// facingH = 'horizontal facing' ( 1 or -1) (this sets our image_xscale when we draw)
// facingFB = 'facing Front/BACK' (0 or 1) (indexes an array that holds front/back versions of the playr sprite.)
// z  =  Fake z axis variable. Basically it just gets added to the y axis in most case to simulate going 'up' when the player jumps. Mostly used for drawing. But it also gets used to check against the 'height' of blocker objects, which the player can get up on.

   if isPlayerControlled // if you're possessed by the player, orient body towards mouse.
       {
       if mouse_x < x {facingH=-1} else{facingH=1;}
       if mouse_y < y-70+z{facingFB=1} else{facingFB=0;}
       }
   else // Facing for AI -----------------------------------------------
       {
       if instance_exists(targetID) //if there is a target, face target.
           {
           if targetID.x < x {facingH=-1} else{facingH=1;}
           if targetID.y < y+z{facingFB=1} else{facingFB=0;}
           }
       else //if not, face where you are moving to.
           {
           if point_distance(x,y,moveTargetX,moveTargetY) > 5 // only update if you are moving.
               {
               if moveTargetX < x {facingH=-1} else{facingH=1;}
               if moveTargetY < y-70+z{facingFB=1} else{facingFB=0;}
               mouseDir = point_direction(x,y-70+z,moveTargetX,moveTargetY-70)
               }
           }
All hand animations are run by this thing below, which basically tweens the hand positions to points that are stored in a bunch of Ds_queues, and goes to the next queue when its got to where it's supposed to be. The Queues are filled by animation script that are called by swinging a weapon or some other trigger.
====================================================================================================
Code:
// ARM ANIMATION QUEUE ---------------------------------------------------------------------------------------
var i = 0;
repeat(2) // do for both hands.
{
if handActionDone[i] //  ((huh.. okay I just noticed this.. it's wierd and I don't know why it's here..but I'm afraid to remove it now... ))
   if !ds_queue_empty(dsqHandRotationTarget[i])
       {
       handRotationTarget[i] = ds_queue_dequeue(dsqHandRotationTarget[i])
       handRotationTween[i] =  ds_queue_dequeue(dsqHandRotationTween[i])
       handXoffsetTarget[i] =  ds_queue_dequeue(dsqHandXoffsetTarget[i])
       handYoffsetTarget[i] =  ds_queue_dequeue(dsqHandYoffsetTarget[i])
       handTween[i]         =  ds_queue_dequeue(dsqHandTween[i])
       handAnimTimer[i]     =  ds_queue_dequeue(dsqHandAnimTimer[i])
       handActionDone[i]=false;
       }
else
   {
   // figure out what your idle position should be, and go back to it.
   // I snipped this because it makes no sense without knowing what the variables involved are.
   }

// Next is a section that tweens the variables you see above.  ---------------------------------------------------

// and finally down here is another section that checks if the hand position and rotation are close enough to their destination to call it good. If they are, handActionDone[i] = true; and hands will tween to their idle positions.
====================================================================================================


Enemies use something a lot simpler, essentially I just have a ton of 2D arrays filled in with sprite info. ex:

Code:
var _sprF = spr_slime_idle_0; // 'sprite Front'  sprite to use to initialize ALL front sprite entries.
var _sprB = spr_slime_idle_0; // 'sprite Back'  sprite to use to initialize ALL back sprite entries.

// IDLE ANIMATIONS --------------------------------------------------------------------------------------------------------------------
animIdle[0,0] = _sprF;   /**/   animIdle[0,1] = _sprF;   /**/   animIdle[0,2] = _sprF;   /**/   animIdle[0,3] = _sprF; /**/
animIdle[1,0] = _sprB;   /**/   animIdle[1,1] = _sprB;   /**/   animIdle[1,2] = _sprB;   /**/   animIdle[1,3] = _sprB; /**/

// MOVE ANIMATIONS ---------------------------------------------------------------------------------------------------------------------
animMove[0,0] = _sprF;   /**/   animMove[0,1] = _sprF;   /**/   animMove[0,2] = _sprF;   /**/   animMove[0,3] = _sprF; /**/
animMove[1,0] = _sprB;   /**/   animMove[1,1] = _sprB;   /**/   animMove[1,2] = _sprB;   /**/   animMove[1,3] = _sprB; /**/

//and many others...
==========================================================================================================================================
I'm just initializing default variables above... In a real case at least some of these array locations would have different sprites in them. But it's important that all they arrays be filled by -something-. I initialize everything to the idle anim, so if an animation that doesn't really exist gets called, it just plays the idle and isn't tooo noticeable.

Anyway. in this case, slimes don't really have a 'front' or 'back', so everything gets the same sprite for both categories. The First index of the 2D array corresponds to Front or Back (Enemies also have the facingH and facingFB variables) and the second number is the index for the actual animation. So right now I can have 4 sprites per category, but practically it can be any number. I'm considering using a format besides an array (grid?) that might be more versatile. But arrays are simple so for now that's what we got. ;)

It's also important to note that both the front and back animations should the have the same number of frames, or everything might explode catastrophically.

Anyway, to trigger an animation, I have this script:
Code:
//scr_sprite_anim_set ======================================================================
var _anim = argument[0]; // animation category (i.e animIdle or animMove, from above)
var _index = argument[1]; // the animation Number (0 - 3, or -1 to choose randomly) ((the 2nd array index from above))
var _time = argument[2];  // How many frames to play animation for. (or if -1, set length to number of frames.)
var _prio = argument[3];  // animation priority (higher values interrupt and override lower ones.)
// SUGGESTED ANIM PRIORITIES [Idle = 0] [fiddle = 1] [Move = 2] [Attack Charging = 3] [Hit = 4] [Knockdown = 5 ] [All attacks = 6] [Dead = 7]


if _prio >= animCurrentPriority // if the anim priority we are setting is higher than the current one.
   {
   if _index == -1 { _index = irandom(array_length_2d(_anim,1)) } //choose a random animation from the category.
   animCurrent[0] = _anim[0,_index]; //set the front animation from the category, with the index we chose.
   animCurrent[1] = _anim[1,_index]; // set the rear version of the animation.

   if _time = -1 {_time = sprite_get_number(animCurrent[0]) * 4 } // *4 as sprite speed is 15 and room speed is 60.
   animTimer = _time;
   image_index=0; // start from the first frame.
   image_speed=1; // just in case...
   animCurrentPriority = _prio;
   }
The priority check happens so keep animations making 'sense'. for instance, if the enemy is moving, it'll probably be scripted to play a moving animation. But if it's also attacking, it'll also want to be playing an attacking animation. Obviously we want to show the attack more than just the enemy walking, so we give the attack a higher animation a higher priority than the move.


And in the step event, we basically just count down the animation timer. When it hits zero, we go back to idle:

Code:
//scr_sprite_animaton ======= (yes, it's actually misspelled. -_- I never noticed until just now. That's autofill for you.) ====================================================================

// processes animations.
// time out animation, and Reset to idle pose if other animations have timed out.

if image_index = sprite_get_number(animCurrent[0]) {image_speed=0}else{image_speed=1} // hold on the last frame if timer > animation length.. Not sure if this works, actucally, I haven't tested it.

if animTimer <= 0
   {
   animCurrent[0] = animIdle[0,0];
   animCurrent[1] = animIdle[1,0];
   animTimer = 60;
   animCurrentPriority = 0;
   image_speed = 1;
   }
else
   {
   animTimer--;  //count down animtimer.
   }
...and elsewhere the sprite_index is set to animCurrent[facingFB] before drawing.

IMPORTANT TO NOTE!!! The current system does NOT have mechanism for switching correctly between front and back sprites. (currently it'll jump back to frame 0 with every switch) That's another of the things I have to fix later, I just wanted to get the basics working before my time was up. -_- I think I may need to either find a way to preserve the image_index through sprite changes, or just make my own frame index variable. Haven't thought about it that much yet. : /

So that's it, pretty much.. hope it makes some sort of sense. I'm a self-taught programmer so I have no idea what best practice in most cases. Apologies if this made anyone cry. :/
But if you have any questions feel free to hit me in PM's. :)

edit: Just now remembered where I remember your name from. Your project is totally amazing. Best of luck!
Hey That´s very similar from what I´m doing... but I have no control on the index... What i generally do is put a alarm for the animation on some cases

For the player animation I need to handle many different equipments and directions for the isometric perspective... So i also use an array of sprites and run a script to render
Code:
///scr_draw_equipment(action,direction)

var action = argument0;
var direct = argument1;

if(inventory.equip_arr[0] != 0){ //WPN
    var sprWpn = inventory.currWpn[action, direct];
    draw_sprite(sprWpn,image_index,x,y);
}
if(inventory.equip_arr[1] != 0){//ARMOR
    var sprArm = inventory.currArmor[action, direct];
    sprite_index = sprArm;
    //draw_self();
    draw_sprite(sprArm,image_index,x,y);
}else{
    sprite_index = arr_default_spr[action, direct];
   // draw_self();
   draw_sprite(sprite_index,image_index,x,y);
}
To keep the sprite information, I use the Item to manage it. It has a DS_MAP with the sprites informations. So when the equip is created, he already knows all the sprites that it contains:
Here it´s the item creation code when the equip drops on the floor :
Code:
//equiped sprites

/* ATTACK */
item.arr_item_equiped_spr[ATTACK, RIGHT]     = asset_get_index(string(sprAux)+'_atk_r');
item.arr_item_equiped_spr[ATTACK, UP_RIGHT]  = asset_get_index(string(sprAux)+'_atk_ur');
item.arr_item_equiped_spr[ATTACK, UP]        = asset_get_index(string(sprAux)+'_atk_u');
item.arr_item_equiped_spr[ATTACK, UP_LEFT]   = asset_get_index(string(sprAux)+'_atk_ul');
item.arr_item_equiped_spr[ATTACK, LEFT]      = asset_get_index(string(sprAux)+'_atk_l');
item.arr_item_equiped_spr[ATTACK, DOWN_LEFT] = asset_get_index(string(sprAux)+'_atk_dl');
item.arr_item_equiped_spr[ATTACK, DOWN]      = asset_get_index(string(sprAux)+'_atk_d');
item.arr_item_equiped_spr[ATTACK, DOWN_RIGHT]= asset_get_index(string(sprAux)+'_atk_dr');

/* BOW ATTACK */
item.arr_item_equiped_spr[BOW, RIGHT]     = asset_get_index(string(sprAux)+'_trow_r');
item.arr_item_equiped_spr[BOW, UP_RIGHT]  = asset_get_index(string(sprAux)+'_trow_ur');
item.arr_item_equiped_spr[BOW, UP]        = asset_get_index(string(sprAux)+'_trow_u');
item.arr_item_equiped_spr[BOW, UP_LEFT]   = asset_get_index(string(sprAux)+'_trow_ul');
item.arr_item_equiped_spr[BOW, LEFT]      = asset_get_index(string(sprAux)+'_trow_l');
item.arr_item_equiped_spr[BOW, DOWN_LEFT] = asset_get_index(string(sprAux)+'_trow_dl');
item.arr_item_equiped_spr[BOW, DOWN]      = asset_get_index(string(sprAux)+'_trow_d');
item.arr_item_equiped_spr[BOW, DOWN_RIGHT]= asset_get_index(string(sprAux)+'_trow_dr');


/* BLOCK */
item.arr_item_equiped_spr[BLOCK, RIGHT]     = asset_get_index(string(sprAux)+'_block_r');
item.arr_item_equiped_spr[BLOCK, UP_RIGHT]  = asset_get_index(string(sprAux)+'_block_ur');
item.arr_item_equiped_spr[BLOCK, UP]        = asset_get_index(string(sprAux)+'_block_u');
item.arr_item_equiped_spr[BLOCK, UP_LEFT]   = asset_get_index(string(sprAux)+'_block_ul');
item.arr_item_equiped_spr[BLOCK, LEFT]      = asset_get_index(string(sprAux)+'_block_l');
item.arr_item_equiped_spr[BLOCK, DOWN_LEFT] = asset_get_index(string(sprAux)+'_block_dl');
item.arr_item_equiped_spr[BLOCK, DOWN]      = asset_get_index(string(sprAux)+'_block_d');
item.arr_item_equiped_spr[BLOCK, DOWN_RIGHT]= asset_get_index(string(sprAux)+'_block_dr');

AND SO ON.....
When I equip the item, all the information is contained into that ds_map object:

Code:
        if(invAux.box[# xx, yy] == 0){
            invAux.box[# xx, yy] = item_id;
            invAux.count[# xx,yy]++;
            show_debug_message("the inventory added" + string(item_id));
            //add the item unique atributes to the item_box
            var itemDS = ds_map_create();
            ds_map_add(itemDS,'item_name',item.item_name);
            ds_map_add(itemDS,'item_id',item.item_id);
            ds_map_add(itemDS,'item_lvl',item.item_lvl);
            ds_map_add(itemDS,'item_unique',item.item_unique);
            ds_map_add(itemDS,'item_unique_id',item.item_unique_id);
            ds_map_add(itemDS,'item_icon_spr',item.item_icon_spr);
            ds_map_add(itemDS,'item_drop_spr',item.item_drop_spr);
            ds_map_add(itemDS,'arr_item_equiped_spr',item.arr_item_equiped_spr);
            ds_map_add(itemDS,'type',item.type);
            ds_map_add(itemDS,'dmg',item.dmg);
            ds_map_add(itemDS,'cost',item.cost);
            ds_map_add(itemDS,'atk_rating',item.atk_rating);
            ds_map_add(itemDS,'item_atr',item.item_atr);
            ds_map_add(itemDS,'equiped',item.equiped);
            ds_map_add(itemDS,'hotkey_slot',item.hotkey_slot);
            ds_map_add(itemDS,'item_atk_scr',item.item_atk_scr);
            
            //add to the box
            ds_map_add(invAux.box_items,item.item_id,itemDS);
            return true;
        }
    }

Hey and thanks for the cheers! Maybe I´ll set a demo in the end of this month! =)
 

Gravedust

Member
Post-weekend update!

Managed to make some decent progress, and have a few things to show off:

As the major project for this weekend; Basic potion functionality is in. This comes along with an expansion of the inventory/equipment system, and lays part of the foundation of finally implementing Skills. (though we're still not ready for that quite yet...)

It comes with a nice drinky animation too..

The sprite being used is the drop item drop sprite currently, I'll fix it so it looks right.

Speaking of animation, we now have the ability to frame-swap hand sprites, so we can mix gestures into emote anims.
Still needs a bit more work, including giving the hands a bit more contrast, since they're small, as well as some minor alterations to correctly handle things like pointing. (Because I WILL NOT REST until I have written scr_anim_youreprettygood)


Spent some time experimenting with palletizing sprite effects, to the end that since elemental damage is a thing that exists and (hopefully) matters, a clear indication of what element something is would be nice. So if a weapon or skill has an element, all it's effects are automatically colored appropriately. This should (again hopefully) help players know at a glance what's what, And if you've got 90% flame resist, sure, go ahead and roll around in that orange/red damage effect if you want.
(That's Arcane and Poison, right there.)

There's also now a palette-shift on hit for enemies:

(by the way, she's always been named Tess because Test, get it?)

And since I mentioned I would post some AI gameplay, here you go, though obviously this is still miles and miles from where I want to go; Hey, it works. :3


Couple things to note:
I'm yellow (just trying to stay out of the way) and the bot is white.
Potions presently have a very short cooldown for testing purposes, you won't be able to chug that fast in a real game. >.> The bot is drinking so often because at LVL1, base HP is 30, and so every slime hit knocks off a significant portion of health which the bot is trying to recover. (god mode is on, tho.) Also, as I figured out later, while the Potion is marked as a self-only skill, the healing tactic skill evaluation doesn't yet take that into account. (whoops..) So if you notice, once I take enough incidental damage from the slimes, the bot is probably also trying to heal ME, though of course it can't because the potion skill effect is self-only. I first noticed that after I'd returned to the HUB with low health and the bot I'm teamed with is chugging constantly. :p Welcome to the wonderful world of "AI: Why the hell is it doing that?"

Anyway, this clip also represents a bot in a very bot-like state. It likes to swing with both weapons exactly as soon as they are off cooldown, and a couple of times it does essentially instantaneous target switching to kill one enemy and hit another nearby one about 5 frames later. So, at the moment it's very efficient (which is good) but also utterly inhuman (which is bad) So one of the things I will have to do further down the road is tone it down to bring it more in line with what an actual player can do (with the ultimate goal of course being to teach it to mimic the player.) and act more relatably and generally less terrifying...

But generally I'm pretty happy with their performance right now. They're good at adapting to changes to weapons and weapon charge levels as I make them, and as soon as I implemented potions they knew how to use them, thanks to the unified skill variables. They're still pretty shaky as a group; at the moment they don't coordinate at all except by chance, (well, as mentioned they can heal one another, teeeechnically, but there are no non-potion healing skills for he player side, yet, so they just stare at you and drink...) but that'll be something I hope to work on soon.

Anyway, it was a pretty good weekend. There's a fair amount of cleanup to do, but I'm pleased with that I got done. :)
 

Gravedust

Member
Friday Update!

This week was mostly about fixing and consolidating changes from last weekend;
I made it so that potions that are on cool down cannot be moved or dropped, to avoid a (very obvious) exploit. I also fixed the hand sprites, adding an outline so the gestures are more visible. (At some point soon I will start making glove/gauntlet sprite sets, which will show on the character when equipped,) Additionally, corrected an issue with the AI processing 'blank' skills that it didn't really need to consider.

But most of this week has been spent doing sprite work, specifically working out a process of sprite animation that looks alright (or at least consistent) and won't take seven hundred billion years. I would love to have fluid, drawn-from-scratch frames for everything, (youtube figured out I was interested in sprite animation and now I have a million duelyst animation vids clogging up my recommendeds. Pretty stuff, and extremely dynamic. ) but given the size of the sprites I am working with and the fact that it's just me doing all this pixel wranging in addition to programming, I don't think that's very realistic for this project.

So my aim presently is to reuse as much as I can. Taking the Gerblins as an example, I have my base art drawn out already, and in layers. So I can essentially treat that base sprite like a paper doll, rotating things as needed to hit the poses I want, and flesh out the basic motion. After that is done, we clean up all the rotated sprite bits (since pixel art @#$%^ HATES being rotated. Fun hint: set interpolation to NEAREST NEIGHBOR, if you are using Photoshop) and reshade them in their new positions/orientations.

Here's the result of that process:

( www.youtube.com/watch?v=osOORiPzrpY )

It works! …But as you can probably see, you can only get so much range of motion without needing to draw custom frames for certain parts. But I guess we can burn that bridge when we come to it.

It's also worth noting that this animation is actually only half-done. -_- The version from the rear also needs to be completed. (Though the work of posing has already been done for us. The silhouettes for the front and rear are almost identical, so I should be able to use visually align the back version based on the front version, and shave 9/10's off the time needed for posing.)

So anyway. I guess I am pleased with the results so far, but I'm looking at a daunting amount of time needed to do the animations I will need order to get the amount of enemy variety I'd like. But fortunately that won't hold up an alpha release.

Anyway. It's shaping up to be a busy weekend, but I'm excited to see what I can get done in the time I've got.
 
F

Felipe Rybakovas

Guest
Hey, Can I ask how you are doing the damage font scale?
 

Gravedust

Member
Hey, Can I ask how you are doing the damage font scale?
Sure. :)

It's been a while and I don't have the code in front of me, but IIRC it goes something like this:
Code:
>>>DISCLAIMER:<<< I wrote this in notepad, and things I write usually break the first time I try them.
So if something looks blatantly wrong, it probably is. ;)

====================================================================
// === obj_damage_popup ============================================

###################################################################
CREATION EVENT ####################################################
###################################################################

phase = 0; // indexes X and Y scale targets. Increases by 1 once scale targets are reached.
tweenRate = 0.05; // how fast to tween. (higher = faster.) ( >1 or <=0 causes the universe to explode )

// SET PHASE SCALE TARGETS ==========================================================================
// Basically these are the X and Y scales we are going to draw the text at. Once one set of scales is reached
// the next one will become active.

// Start invisible
scaleXtarget[0] = 0;
scaleYtarget[0] = 0;

// 'bounce' horizontally
scaleXtarget[1] = 5;
scaleYtarget[1] = 3;

// shrink to a decent readable size
scaleXtarget[2] = 2;
scaleYtarget[2] = 2;

// For more stages, just keep adding to the arrays...


// Initialize our draw variables ---------------------------------------
// These will be the scale values that go into draw_text_transformed();
drawX = scaleXtarget[phase]; //set to phase 0 to start.
drawY = scaleYtarget[phase];

###################################################################
STEP EVENT ########################################################
###################################################################

if phase < array_length_1d(scaleXtarget)  // If you are not at the end of your phase array… (using an arbitrary array to gauge array depth)
   {
   // If the draw scale is 'close enough' to the target scale, advance to the next phase
   if ( abs(scaleXtarget[phase] - drawX) < 0.1 ) && ( abs(scaleYtarget[phase] - drawY) < 0.1 )
       {
       phase ++;
       }
   }
//  ---------------------------------------------------------------------------------------------------------

// Tween or otherwise increment draw values towards scaleTarget[phase] values
drawX += ( scaleXtarget[phase] - drawX  ) * tweenRate;
drawY += ( scaleYtarget[phase] - drawY  ) * tweenRate;

###################################################################
DRAW EVENT ########################################################
(Probably draw_end, to keep it appearing above everything)
###################################################################

draw_text_transformed(x, y, WhateverYourDamageIs, drawX, drawY, 0);

========================================================================================
I …Think that's what I did? Or at least is pretty close to it. There are obviously some extra bells and whistles like y--; so they rise, and some alpha decay. The trick is mostly finding nice values to tween to.
 
Last edited:
F

Felipe Rybakovas

Guest
Sure. :)

It's been a while and I don't have the code in front of me, but IIRC it goes something like this:
Code:
>>>DISCLAIMER:<<< I wrote this in notepad, and things I write usually break the first time I try them.
So if something looks blatantly wrong, it probably is. ;)

====================================================================
// === obj_damage_popup ============================================

###################################################################
CREATION EVENT ####################################################
###################################################################

phase = 0; // indexes X and Y scale targets. Increases by 1 once scale targets are reached.
tweenRate = 0.5; // how fast to tween. (higher = faster.) ( >1 or <=0 causes the universe to explode )

// SET PHASE SCALE TARGETS ==========================================================================
// Basically these are the X and Y scales we are going to draw the text at. Once one set of scales is reached
// the next one will become active.

// Start invisible
scaleXtarget[0] = 0;
scaleYtarget[0] = 0;

// 'bounce' horizontally
scaleXtarget[1] = 5;
scaleYtarget[1] = 3;

// shrink to a decent readable size
scaleXtarget[2] = 2;
scaleYtarget[2] = 2;

// For more stages, just keep adding to the arrays...


// Initialize our draw variables ---------------------------------------
// These will be the scale values that go into draw_text_transformed();
drawX = scaleX[phase]; //set to phase 0 tos tart.
drawY = scaleY[phase];

###################################################################
STEP EVENT ########################################################
###################################################################

if phase < array_length_1d(scaleXtarget)  // If you are not at the end of your phase array… (using an arbitrary array to gauge array depth)
   {
   //If the draw scale is 'close enough' to the target scale, advance to the next phase
   if ( abs(scaleXtarget[phase] - drawX) < 0.1 ) && ( abs(scaleYtarget[phase] - drawY) < 0.1 )
       {
       phase ++;
       }
   }
//  ---------------------------------------------------------------------------------------------------------

// Tween or otherwise draw values towards scaleTarget[phase] vales
drawX += ( scaleXtarget[phase] - drawX  ) * tweenRate;
drawY += ( scaleYtarget[phase] - drawY  ) * tweenRate;

###################################################################
DRAW EVENT ########################################################
(Probably draw_end, to keep it appearing above everything)
###################################################################

draw_text_transformed(x, y, WhateverYourDamageIs, drawX, drawY, 0);

========================================================================================
I …Think that's what I did? Or at least is pretty close to it. There are obviously some extra bells and whistles like y--; so they rise, and some alpha decay. The trick is mostly finding nice values to tween to.
tks buddy! =))
 

Gravedust

Member
Midweek update!

Over the weekend I rigged up proper stat generation for armor types. A lot of tuning will still be required, but they are now correctly generating stats based on quality, tier, 'brand', and allowed bonus stats per slot (So no +movement speed bonus on Helmets, for instance)

I also have more or less completed the back version of the Gerblin running sprite. I was able to use the front version of the sprite as a guide for animating the back, but some parts did need to be redone from scratch. I expect that my speed will improve over time, but as of now it looks like animating enemies will definitely be a pretty serious bottleneck.



In other news: After giving it a LOT of consideration, I think I'm going to be increasing the size of the player characters somewhat, mostly so I can put a little more detail into facial expressions, armor, and the like. (mouths and hands specifically are tiny and annoying to render.) And generally I think I can do cooler things with armor and such with the extra real estate.

New size on left, old size on right.

(not to make it an unfair comparison, the image on the right is a little blurrier than normal, I notice. It's either due to host compression or because I used the wrong setting when reducing... But I'm sure you get the idea...)

…This comes with a few logistical problems, (and needing to re-output all my player sprites at a new size) But I think it's probably a worthwhile change. I'm going to try to do that this weekend and hopefully it won't be a huge disaster.

In other news, hand animations have finally been sorted out, and gloves are now shown on characters:
Also, Belts! (not yet implemented, waiting till after the sprite redux this weekend, but the art is done.)
So, here is (pretty close to) how the three tier 1 armor sets will wind up looking, all included.

Of course you can mix and match, etc.

Anyway, has been a fun couple of days. :) Animation work will continue, and adding on-hit effects for weapons is next on the to-do list (though the stuff on that list doesn't always get to-done even when it's at the top…)
 

Gravedust

Member
After giving it a LOT of consideration, I think I'm going to be increasing the size of the player characters somewhat ... …This comes with a few logistical problems, (and needing to re-output all my player sprites at a new size) But I think it's probably a worthwhile change. I'm going to try to do that this weekend and hopefully it won't be a huge disaster.
IT WAS A HUGE DISASTER.

Or technically, a pretty minor disaster that I am going to nevertheless need to spend a lot of time fixing.. The gist of the problem is that the new size reduction I'd chosen was non-square (I knew this would be a problem but I was hoping it would not be a showstopper) and while most of the sprites output at that size fine, certain of the sprite strips (hands specifically) were very hard to get sized properly and in the end usually needed to be size-adjusted by a pixel or three, resulting in nasty interpolation blurring in the final result. A minor thing, but enough to set me off. ;) Another, larger problem was that the interpolation result was not predictable, so I would never know exactly how a sprite would turn out until I actually resized it to the final size.

Anyway, In the final estimation, just redoing all the sprites now would be less heartache in the long run than having to deal with art that does not export how I think it will.

So I have now done things the 'right' way by basically increased all the player sprite art by an amount to where I would be reducing by a square value, but still have the larger end sprites that I wanted. There is nothing I need to actually re-draw, but the working file is now chock-full of jaggies that need to be smoothed. So that is most of what I have been doing this past week. Along the way though I have made improvements and added detail to the upsized art, which is what I was going to do anyway, so it's not totally wasted time at least. :)

Other additions include re-enabling Axes and Greatswords as weapon drops using the updated item generation scripts, and adding a slight delay between melee attacks for AI-controlled characters to bring them more in like with the reaction times you could expect from a human-ish person. I additionally added some code to helps space out AI swing times, so instead of swinging weapon0 and then immediately swinging weapon1 a few frames later in a kind of double-tap, they will now try to space their melee attacks to keep up a more or less even left-right-left-right swing rate, like humans tend to.

This is also technically the first step towards introducing player-generated behavior data into the way the AI operates, (I rigged up a bit of code that pays attention to the time between player button presses, so I could manually tune the swing timers for the AI and get an idea of what good values for each weapon class are.) but we probably won't be looking into that seriously for some time yet.

The other recent addition has been the introduction of a Knockdown state. Basically if you take too much damage too fast, you are stunned (the player sprites actually fall over) and are unable to move or act for a brief period of time. (2 seconds as a baseline) Both the amount of damage needed to trigger a knockdown and how fast you recover from one are dependent on your Defense stat, and can also be improved via gear bonus stats. Important for tanks. Fortunately enemies are susceptible to knockdowns as well.

Also in the way of miscellaneous additions, attack skills can now be set to ignore some or all of at the target's armor.

So, despite a big 'ol timesink in the player art department things are still progressing decently well. :)
 

Gravedust

Member
Whew! Still here!!

Things got a little crazy for a few weeks with non-dev stuff, so not much visible progress, but things are still trucking along.

Still working on cleaning up the resized player art, but have taken some steps towards full skill implementation. Skills are now saved and loaded with character info, and I've done a minor overhaul of the way players handle drawing hand items in order to show skill-related sprites at the player hand positions and also allowing for animated weapon sprites, skill effects, or other items. (We will probably eventually have animated sprites in the helmet, chest and belt(?), armor slot as well.) This was all actually shockingly easy to do; since skills are a pretty big part of the game, I had figured on several hours of implementation, and so I just sort of sat there blinking after I had player NPCs shooting prototype fireballs after about 15 minutes. Of course this turned out to be the result of hours and hours and hours of planning and refining the way skills are handled, and a lot of skid-greasing done on the process of adding new ones. (It also helps that skills are actually a LOT less complex than weapons) I guess I should have expected it, but it was still a really nice surprise to just plug in the new stuff and have it work immediately. :p

Anyway, I have also started adding animations for skill use so skills can have warmup, cast and cooldown animations and poses like weapons do, and clearing up a few in the animation system.

Also performed a minor tweak to the AI to make units more likely to choose targets that are not already being attacked.
…I feel like I mentioned this before, but I can't seem to find that now. So.. Eh.

Anyway! The next big step towards skill implementation seems to be (aside from adding more prototype skills for testing) making a stat box menu where skills can be selected and bound… I may take the opportunity to redesign the entire stat box and menu system while I'm at it; it works but it's kind of clunky and a mess to deal with.

Aaaand a slime projectile attack anim I made a while back:
 

Gravedust

Member
:eek: < MFW I insert the object I've been working on into an empty room and the FPS immediately drops from 3000 to 17.

…But fortunately it was just a problem with a tile-fill script I wrote, or specifically that my standard "no image" placeholder image is a 1x1 transparent pixel, and I was accidentally trying to tile-fill several 128x256 px boxes with it. It did not like that. :p Thankfully it was a really easy fix, but boy was I spooked for a bit.

I've been working on a new (and hopefully improved) menu/UI/Window system, which I hope will make building UI elements a lot easier (Since ATM I am hand-coding each one, and I really want to not do that, because huuuurrrrrgggghhhhhh.) The end result should be the ability to (relatively) quickly define a new UI element, with options for registering mouseover, being moveable, resizable, depth-sortable, having a tiled background, etc. They must also be able to be altered with by other systems. (So for instance if I create a popup window that shows the stats of an item, the inventory system can shove the pertinent strings and icons into the right places in the window, which will display them. (It's also equally possible to create a window with instructions on how to get all this info itself) ) I am also looking into the ability to attach 'gadgets' to open windows, which are basically separate objects that 'ride' the window, and can have their own functionality. (so for instance, I could attach some of my generic button objects to a moveable UI window as gadgets, and create a moveable menu.

Yadda yadda, etc etc. There are many like it, but this one is mine.

So far it's going well, but there's still a LOT to do. As with most things, I am trying to make this as modular as I can, so I can use it in future projects as well.

In other news, I have finally finished cleaning up all the upscaled character art, which is all now snugly imported and working. Arm animations and hit volumes need some adjustment, since everything is a bit bigger now, but hopefully that won't take too long. Leg animations needed to be redone, but should now also be a bit easier to do in the future, thanks to a bit of streamlining (and not being a total idiot about how I set up my Spine files) I also squashed a bug in the animation system regarding the offhand not resetting to its idle pose correctly, and some small fixes to item generation (such as the dastardly potion that heals for 0 health. :p )

Beyond that, further system development is pretty much held up behind the new UI system, (Which should make a ton of things a lot easier) but I have a decent amount of sprite work and some other drawing tasks to do also, so hopefully I should have some new art assets to show soon-ish.
 

Gravedust

Member
Howdy folks!

Been a while since the last update so I figured I'd crank out one for the new year. :)

Mostly what I've been up to is working on my new window system, which is coming along well, but pretty slowly. Since my plan it to use this system for… Well basically all menus for all my GM games for the foreseeable future, I am putting in a lot of functionality and versatility. And since so much is going to be layered on top of this system, I'm spending a lot of time testing things and making sure everything is rock solid at the foundation.

So far I have it generating windows that can be subdivided into sub-windows with user-defined values for number per row, number per column, cell spacing (which can be made variable to evenly space them out in their available area, subwindow Width (which can again be made variable to fill up the available space)

Each subwindow registers mouseover, and so this is a pretty easy way to quickly set up things like inventory grids.

So, if you look at the previous post, you can see I'm chewing through the desired features list. Right at the moment I am looking at adding interior and exterior bordering sprite sets, so you can add fancy sprite borders. Next up will be the ability to house 'gadgets' like drag-boxes and gauges.

Soo, the last few weeks have been lots and lots of coding, (and holiday stuff, of course) and there's probably some time left to go before I get to move on to something else.

In the mean time I've been doing more work fleshing out how I'd like skill selection to work, as well as some of the finer points of skill implementation. Looking forward to getting started on that as soon as the window stuff is closer to being done.

Haven't done much in the art department, but I have been continuing to experiment with sprite animation in anticipation of doing more attack anims for enemies.

But unrelated, here's a sprite from a quickie side-project I am doing:

Started out as an Xmas gift, and is being now being fleshed out somewhat. It's been fun to work on. :)
 

Gravedust

Member
AND WE'RE BACK!!

The window thing took forever, (and some of my time was eaten up by my side project, which is actually coming along really nicely) but I now once again have SDS development back on the front burner.

As far as the window system: It works! And it works pretty well, actually. I achieved all my goals except for window-resizing and on-the fly window restructuring, and those I skipped pretty much because while they're cool, I'm not at the moment sure that I'll actually ever need either. -_-

Likewise, a lot of the finer bits of functionality will be filled in on an 'Okay, I need that now, better do it...' basis. But the point is I now have a pretty stable framework that I can add new stuff to when it becomes appropriate.

It took a long time, but I learned some good stuff and now have some swiss-army code that should help me a lot in the future.

…Implementing the new window system has also convinced me I need to rewrite my inventory and equipment code, (for the 3rd time). -_- But I'm… just… not going to do that now. It works well enough to keep on working as is for the time being, and believe it or not I am still focused on getting a playable alpha out, so things like a UI rewrite will wait till after that. :p

But moving on:

After doing a lot of notepadding I believe I have a pretty good idea how I want skills to work, and I have a basic path laid out for how I want skill progression and expansion to go.

The cliffs' notes version is: As you level you gain access to Specializations (groups of related/themed skills, i.e. Pyromancy, Berserker, Hexes, etc.) from which you unlock passive or active abilities which you can equip on your character. More specializations are unlocked as you go, and as you level you also earn Rank points, which you can use to improve your skills.

Any character can have any specialization combination, so by choosing you specialization skills and passives, and distributing your attribute points wisely, (Attributes play the biggest part in determining an ability's raw damage/healing etc.) you essentially get to 'build' custom classes. I intend for a respec option to be available, so if for some reason you don't like the way a character is working out, you can be refunded most if not all of your specializations, skill choices, and skill rank points.

But all that will happen a bit further down the road. The main task at hand right now is to get all the skill mechanics actually working, (my attack template objects will need some expanded functionality to handle everything I will need them to do) and mock up a number of skills to test with, including making sure the AI knows how to use them correctly. This may include expanding the AI to finally start handling things like Roles and Tactics. This will probably make for slow going, but it is also the kind of work I tend to like, so I'm looking forward to the mess that this will be. :p
 
S

SVG

Guest
Man you're really going large haha, are you working by yourself? I have 9 unfinished games cause they were all too large lol, my 10th one now is the smallest I've ever tried, and it's still gonna take a month. I applaud your dedication and hope you never lose sight of your dream. With that said I hope this project isn't too big to ever finish alone. Yeah and I understand about the family thing too lol, my brother loves the business side of things but hates programming and nobody really understands what I'm talking about. He's getting into art though and helping me with this small project.

Do you have anyone helping you out? It's not like I'm offering to help (WAY too busy lol) but would love to see ppl like yourself working with others, or even one person, on something that you can share your passion with. I've worked on projects for over 2.5 years alone, and I've loved and hated it haha.
 

Gravedust

Member
Yep, it's just me, pretty much.

The size of this project is something I have given some thought to as well, especially since the 1 year anniversary is coming up pretty soon. <_< I will admit to not quite getting the true depth of the time commitment when I first started. It really is system upon system upon system, and sometimes you don't see the next mountain until you get to the top of the one you're on. :p Another big factor is if my life and work schedules land badly, there are days or weeks when I simply don't get any dev time.

But despite all that I am still pretty excited and committed to this project; after almost a year, a couple of nasty rewrites and retouching 80% of my art assets, I'm still pretty jazzed about where it's at, and where I intend for it to go. I think this dev thread actually helps me stick to my guns quite a bit, it's cool to go back and look at my own progress, and always nice to hear people are interested. :)

I think it basically boils down to this being The Game I Wanna Play, and so working on it is still more fun than a chore.

As far as being a 1-man team; the one thing I am really concerned about time-wise is enemy sprite animations. They have so far proven to be VERY time-consuming, and further on will probably be a significant bottleneck in adding new enemies. (Though the palette system will make sure I get as much mileage as possible out of every sprite set) So in the future I could see myself accepting help with that if any were offered. ...I am also pretty bad at sound design, so for everyone's sake I would gladly accept any help in that department once the project is ready for sound. :p

I haaaave been cheating a little in some very small side projects, but I have tried to make sure they stay pretty small in scale and closed-ended. Hopefully one of them will be done enough to share here soon-ish. :)
 
  • Like
Reactions: SVG

Tim

Member
Man, this whole game has such a charming and fun look to it. Really looking forward to watching this develop.

Best of luck!

-Tim
 

Gravedust

Member
Thanks! I picked up B101 for pretty much the same reason. :)




In other news; quick and dirty idle animation for Gerblins, completed but not imported…


Will do some retouching and secondary animation in the hair and ears when I get around to it.
I think as soon as I animate at least a basic attack for them I can get them working as test enemies, so I don't have to fight slimes all the time. :p

Otherwise, still messing around with skill stuff, finalizing the saving and loading thereof, and making sure keybinds work. Making progress, but schedule has still been pretty blocked up lately. : /
 

Gravedust

Member
And we're back! Reports of my demise have been mildly exaggerated.

I have however just been hellishly busy for a long time, and then also felt like I needed a bit of a break from SDS for a while to avoid burnout.

I wound up spending a bit of time on this thing:


...Which you can and should play. It's free. :) But with that complete I am ready to put SDS on the front burner again.

So as far as what I've actually been up to: I've -FINALLY- started in earnest on figuring out level architecture. Lancerbird actually runs on a grid-based collision system, which is pretty much ideal for this game as well. So having already figured it out for Lancerbird, it was pretty easy to get it working in this game as well. I was skeptical about gridNav at first, but oh man am I sold on it now.

Anyway, now that I can have levels, it's time to make sure the AI can navigate them, so I spent a little while getting GM's native pathfinding integrated into the AI, so it can get to where it needs to go when it needs to go there. I also needed to throw in some grid checks so AI don't try to hit you through walls. (Unless they have a skill which can actually do that. >.> )

I do still need to write my own A* code at some point, because eventually I want my AI to be able to do things like not walk blindly through AOE effects, or path away from 'dangerous' areas with lots of enemy threat. But we're not there yet, so I'm holding off for now.

Right at the moment though all my architecture is just awfully-colored boxes, so my next step in that direction will be to prototype a tile set to use for the walls to make sure everything looks nice.

The other main dev area has been a specialization and skill selection window, or , basically how you will be able to select and bind the skills your character has access to. I've been using my new window system to build this up, and so far things have been going decently well; I made some test specializations and test skills, and can now get them properly loaded into a character's info and properly displayed in their skill window. The next step will mostly be actually moving the skills into the right slots.

Once this is done I can make some real specializations and skills, which I'm really excited for. :D

The other other dev area has been some quality of life stuff regarding projectile skills; basically adding an invisible 'lock on' for certain projectile skills to make them more likely to hit. Also since it's been a long damn time since the last update, I figured I'd show off some stuff I've had for a while but never actually showed:

Palette swapping! (Thanks Pixellated Pope!)

Which should let me squeeze a lot more mileage out of the sprites it take me a million years to make. -_-

Knockdown!

"They told me this axe was cursed, but what do they kno-HUARRK!!"
 

Gravedust

Member
Believe it or not this project is still alive!

It's just been a loooong time since I had anything visual to show, and dev time for SDS has been squeezed out by some other projects and various other real-world concerns.

But a quick summary of what I've been up to behind the scenes:

+ Automatic level tiler.
Examines the layout of the level and automatically plunks down sprites to make it look pretty. Right now using a test tile set to make sure there are no missed cases being hidden by art, but looking forward to doing a real tileset so the game will finally start looking a bit less horrible. the 3/4 perspective made it a bit of a challenge, but I think it is working out pretty well, especially with silhouettes.

+ New depth-sorting system
Based off this thread here: https://forum.yoyogames.com/index.php?threads/depth-sorting-method-for-gms2-objects-sprites.42868/
which allows for non-objects to be depth-sorted along with objects, so things like level decorations can be depth-sorted without there needing to be an object involved. It also allows objects to be drawn without needing to have a specific depth-sorting parent. Pretty cool. :)

+ UI rework
Heavily in progress right now., the current player stat boxes, inventory grids, and etc. are all being converted to use my new window system, and getting actual sprites instead of being just a pile of draw_rectangle(). It's a slow process and involves some experimentation and expansion of the window system, but so far it is going well.

+ Inventory/Gear rework
Since the new UI requires a rewrite of the gear and Inventory system anyway to merge it with the new window system, my next project will be re-re-rewriting the inventory and gear systems to make them a little more modular and easy to work with.

+ AI improvements
Bots can now heal themselves and others more efficiently. They will also now loot items while out of combat. I am planning to have settings that will determine what they are interested in picking up, so they don't fill their inventories up with grey items while you're trying to farm.

+ Specializations, Skills and Passives

Are now implemented, though all I have are placeholder Specs and Skills at the moment, and some hilariously stupid proof-of-concept Passives. (like the one that makes you randomly bounce into the air, the one that changes your hair color every 2 seconds, and the one that amplifies fire damage by WAY TOO MUCH.) Cooldowns on skills are also now shown visually.

...So it's been a long time in the no-update-because-there's-nothing-to-actually-look-at doldrums, but we're getting there!

Since it's been so long since I've had an update though, I thought I would throw in something special I wouldn't otherwise consider posting: A glimpse at a test dungeon run with some bots. This build is actually from May or so, so it does not reflect a lot of the recent changes I just mentioned, but you can see the new architecture at least, and the glorious debug tileset. (apologies in advance about the sound. It's all placeholder and I usually have it muted. -_- )

The yellow name is me, white names are all bots.


There's obviously a lot about the bot behavior that needs to be cleaned up, and that will definitely be dealt with. I roll my eyes hard every time they act like goofs and there is a LOT more work I plan to put into them in a few different areas. Some of the problems are things I haven't tried to address yet (like clipping with one another, or engaging enemies far away from the player. They always come back though. :p) But in general they do a pretty good job. They do have a definite problem with rubbing their faces on the walls (sigh) as well as trying to shoot through them (siiiigh). But they'll learn.

Anyway. I hope the next update will come a lot sooner! Hopefully I can show in-game clips a bit more often now, as things get more bearable visually. ;)
 

Gravedust

Member
PROGRESS!

It's been slow-ish, but it's been happening. Unfortunately not a whole lot of it has been visual, as per usual, but I have been slowly been cranking out more animations for things like the dealie below, for the Gerblin vanilla attack:

( He just wants to bang on the drum all day )
Still have a few more animations to do for them, but hoping to finally see some Gerblins in-game soon.

Besides that, I have completed complete migration of the player UI to use the new window system, which works great. (though having written it, I can see a few obvious ways the code can be simplified and improved, so reimplementation 3, here we come. :p )

While doing the I also implemented full support for the level-up process, and allocating stats, choosing Specializations, Unlocking and ranking up skills, and a leveling system to tie it all together. Figuring out when exactly to dole out various unlocks to the player is still a work in progress, but that can be adjusted over time.

I have also (finally) established a map template and created some test level layouts, which include random spawn-in and exit areas, as well as prototype enemy spawn spots.

So now it is possible to navigate from level to level, and then back to the HUB. Still no procedural generation, but that's for the future. I've been looking into a few methods (and some marketplace assets) and I'm excited to get to work, but not just yet.

I also finally added proper handling for player characters getting knocked out/dying, including erasing characters on death for Hardcore mode.

So, as mentioned above, next up will be the re-re-reimplementation of the UI Statbox processing scripts, and adding a few more windows for things like player stashes and other containers.

After that I have a big stack of AI improvements that I'm really excited to start working on, including a lot of out-of-combat behavior refinements, and better handling for AOE effects while in combat.
 
Top