tetristar-interactive
tetristar-interactive
Tetristar Interactive
30 posts
The official blog for the small video game development company
Don't wanna be here? Send us removal request.
tetristar-interactive · 8 years ago
Text
A Most Shadowed Descent/ The Order of Chains - A Post Mortem
I have been using Gamemaker since I started seriously working on video games. It started with wanting to test the waters. I wasn’t sure if I really wanted to commit to this hobby so I decided to make a small game called Alive in the Night. I worked on that for six months, although the actual workflow went along the lines of copying line-for-line from reference code online for 90% of the code as well as taking a two month break when my day-job got busy. After that I decided to create a slightly more ambitious game in the form of The Grand Peratrur Nation. Also taking six months, production went a lot smoother and I started to experiment by having about half of the code being of my own creation.
I started working on A Most Shadowed Descent only a few weeks after finishing my last game. I’ve discussed in previous writings about the history of A Most Shadowed Descent and The Order of Chains so I won’t go into detail. All said though I haven’t discussed some general points about how Gamemaker played a part in the production. So let’s answer some questions, shall we?
Note: This will relate specifically to Gamemaker: 1.4 and may not be applicable to other coding languages/versions of Gamemaker.
Tumblr media
How would you describe the development process?
Drawn out, to say the least. I knew with this project I wanted to use as much of my own code as possible. Because of this, I needed to take time to resolve problems that I normally would have just checked for online. This combined with the facts that I changed the way the game played twice in production as well as me taking about half of my spare time to learn other coding languages really stilted the entire process.
What part of the process was most difficult for you?
In total I worked on both A Most Shadowed Descent and The Order of Chains for just over 13 months, and it was very obvious that it was the longest thing I had worked on. Throughout everything my number one difficulty was development fatigue. My creative juices were flowing through the entire project and I knew if I worked on any of them I would potentially never finish A Most Shadowed Descent. This is the whole reason I ever started The Order of Chains, I could continue to work on A Most Shadowed Descent while indulging in something new.
Tumblr media
What frustrations did you have?
In learning a few other coding languages I would hit parts in production where I would try to do something in GML and was unable to without going in a roundabout way. The biggest example of this is my absolute disdain for alarms towards the end of production. I so badly was wishing for some sort of delay function that I could implement so I wouldn’t have to have so much of my code segmented away from itself.
Which functions did you rely most heavily on?
I realized I had been using scripts all wrong right towards the end of production. This came to the forefront of my mind while implementing sound into The Order of Chains. In my previous projects I would add a chunk of code for each sound which was essentially:
If !audio_is_playing(snd_footstep) {
    audio_play_sound(snd_footstep,1,false);
    audio_sound_gain(snd_footstep,global.soundeffects,0);
    audio_sound_pitch(snd_footstep,random_range(.75,1.25);
}
That’s fine at first but over time it’s too much. I realized this and changed how it functions where, whenever I wanted a sound, I would add this code:
scr_play_sound(snd_footstep,false,true);
I would then reference the following script with that:
If !audio_is_playing(argument0) {
    audio_play_sound(argument0,1,argument1);
    audio_sound_gain(argument0,global.soundeffects,0);
    If (argument3 == true) {
        audio_sound_pitch(argument0,random_range(.75,1.25);
    }
}
This made sound implementation ridiculously easy where now I only had to worry about adding a single line of code as opposed to a wall of text. This also helped with upkeep and debugging.
Tumblr media
What would you change?
For those who have played it there are sections when you could potentially catch a glimpse of some unknowable evil in a manner akin to H.P. Lovecraft. I really wanted to do was show this evil via 3D modeling. The idea was something that is 3D in a 2D world functions as a comparison to how Lovecraft describes his monsters as being “incomprehensible”. I didn’t follow through on this because I didn’t have the time nor patience to commit to learning how Gamemaker handles 3D in the way I would want. Essentially, I didn’t want to commit any time to it if I couldn’t make it perfect.
Overall Thoughts?
I am honestly very pleased with both A Most Shadowed Descent and The Order of Chains. My biggest frustrations for the project all stem from the fact that I am using Gamemaker Studio and I really feel as though it is holding back my production. Aside from what was mentioned in here I had many instances where I felt like I was either being held back or that I was somehow a lesser game dev because of my choice of engine.
I’m extremely happy that Gamemaker was available for me to get my feet in the door and helped me feel more confident with my new favorite hobby. All that said I feel as though it’s time for a change. I want to be able to work on games while also working with a coding language that can prepare me for some form of coding workforce. What that will be, who’s to say. Ultimately though, I still want to thank Yoyo Games for creating this game engine.
Tumblr media
Be sure to follow us on Twitter!
0 notes
tetristar-interactive · 8 years ago
Link
Download it here
0 notes
tetristar-interactive · 8 years ago
Text
The Order of Chains Available now FOR FREE!!
Tumblr media
Download it. Enjoy.
0 notes
tetristar-interactive · 8 years ago
Photo
Tumblr media Tumblr media Tumblr media Tumblr media Tumblr media Tumblr media Tumblr media Tumblr media Tumblr media Tumblr media
A Most Shadowed Descent available this Tuesday, July 18th!!
0 notes
tetristar-interactive · 8 years ago
Text
Influenced by H.P. Lovecraft
Tumblr media
My absolute favorite reading material is that written by H.P. Lovecraft. While I completely agree with all the criticism raised against his work I am able to look past this and focus on what I enjoy in it; Cosmic horror the likes of which would cause humans to go mad due to it being incomprehensible. It’s because of my great love for his work that I model so many of the projects I work on after them. I’d like to discuss the newest video games I’m releasing and how they are based on Lovecraft’s work.
I gained inspiration to start A Most Shadowed Descent while playing the Playstation 4 game Bloodborne. It was while reading the descriptions for the runes that you find that I wanted to make some sort of card game using ancient runic symbols. The initial project was going to involve summoning an evil monster and having to use the same runes to destroy it. The constant quote of “Do not call up that which you cannot put down” from The Case of Charles Dexter Ward ringing in my ears.
Tumblr media
After a little bit of playtesting I realized I wasn’t going to be able to play towards those Lovecraftian themes if I didn’t change the dynamic of the gameplay. Because of thisthe game was changed to you having to gather the aforementioned runes while avoiding certain things. In figuring out the manner in which I wanted to gather these runes I could not decide between an ancient tomb in a manner similar to The Statement of Randolph Carter or a museum or library inspired by both The Horror in the Museum as well as the cooperative card game Elder Sign created by Fantasy Flight Games.
I eventually decided exploring a library as I felt that would be a very approachable scenario. My favorite thing to do with Lovecraft’s writing is to share it with people in some way that could introduce them to his entire catalogue. With a library it’s a basic location that can have mild weird fiction sprinkled in without creating an unapproachable scenario.
Tumblr media
...and for the longest time that’s how the game functioned. I had to add in some fail states and decided you would have to find clues on how to cast the runes because if cast the wrong way it could unleash this unknowable evil who blah blah blah. I know, not extremely original but I figure if someone can get past one of the biggest critical aspects of Lovecraft’s work they will be able to enjoy it even more.
It wasn’t until I decided to create a prequel story in The Order of Chains, in which the story of the player’s friend is told, that the influences began to coalesce. I decided he had to have made a deal with some cult who worships the primary Lovecraftian being known as The Tethered. With these cultists think more standard robes and mantras rather than the primitive ones seen in The Call of Cthulhu. By following this train of thought and recognizing all the different cultish aspects that could be followed gave the entire situation a far darker air.
Tumblr media
The culmination of this, however, was recognizing the fact that the main subject of his stories end up in their predicaments either due to an ill conceived curiosity or, in the most horrific cases, tricked by someone trusted. In my case I wanted the player’s friend to have aspects of both. So I looked at my favorites stories and immediately thought of Edward Derby in The Thing on the Doorstep.
It was surprisingly easy to implement that aspect without it hurting any other part of the story. As though it were written into the initial pitch having the player’s friend be betrayed by a former lover worked phenomenally well. I thought about having the body swapping aspect but felt that would take things a little too far with who my target audience was.
The ultimate question I ask myself whenever I finish any project is am I happy with it. Am I pleased with where it ended and did it match or improve on my original vision. I have had a lot of instances where I am quite far off but, in the case of A Most Shadowed Descent and The Order of Chains I would change very little and I feel it’s far better than what I originally thought of. A Lovecraft story that continually pays homage to multiple stories and experiences as it offers a glimpse into what is so great about H.P. Lovecraft.
Follow me on Twitter for more updates!!
Tumblr media
0 notes
tetristar-interactive · 8 years ago
Photo
Tumblr media Tumblr media Tumblr media Tumblr media Tumblr media Tumblr media Tumblr media Tumblr media
The Order of Chains
Available for free July 18
The prequel adventure to the upcoming A Most Shadowed Descent experience the events that caused an unfortunate soul to whither from some unknowable force. A modern day interpretation of the point and click genre, experience lovecraftian cosmic horror in a new way.
0 notes
tetristar-interactive · 8 years ago
Link
0 notes
tetristar-interactive · 8 years ago
Text
One Small Step - A Ludem Dare Postmortem
This last weekend I took part in Ludem Dare 38 the theme of which being A Small World. I could go through the story of how the game was made but, rather than that, I’d like to point out 1 positive takeaway, 1 negative takeaway and 1 thing I wish I could have added to the final product called One Small Step.
Positive: Zoom In/Out
Tumblr media
I have a deep love for strategy games. There is just something that I find very satisfying about effectively implementing a plan that pays off. I’ve toyed with strategy games in the past but one of the things I couldn’t get quite right was zooming. With One Small Step I decided to jump head first and hope I got it right before the deadline.
I initially had created a system that worked pretty darn well. It handled zoom in and zoom out fairly well and allowed me to drag the screen around as needed. The only problem I really had with this though was I couldn’t figure out 2 things; First when zooming out you could zoom past the room size and second when zooming in it would zoom towards the center of the room rather than the mouse.
I worked on these problems for entirely too long before turning to the internet and finding Pixelated Pope’s zoom system. I took that information, made some minor changes, and implemented without a hitch. While I wish I was able to construct my own system for this within the time frame at this point I’ll focus on making a new system for my next project that uses zooming.
Negative: Terraforming
Tumblr media
One of the core concepts behind One Small Step was that not all planets are immediately habitable or not as ideal in its habitability. In order to compensate for this and ensure colonization of the planet can occur the terraforming mechanic was introduced. The initial idea behind it was the player would have the ability to terraform a planet once which would raise the survivability while killing some of the population.
This was an awful mistake.
One of the defining characteristics of games in general is their ability to allow user choice and interaction in a problem solving scenario. The unfortunate issue with my initial terraforming mechanic was the choice of whether or not to terraform a planet was not present. With the old system the correct methodology was always to terraform a planet and then try to colonize it. Choice was removed as the correct play was apparent.
I was able to fix this by making a minor change. Rather than having terraforming kill some population it now increases the population. This creates an interesting situation where the player has to weigh increasing the enemy population but raising survivability for an easier initial colonization or wait until the player owns the planet to receive a boost to that planets population. In my opinion this is a much better way of creating interesting choices while not detracting from the main theme.
Wish List: Random Name Generation
Tumblr media
Something that I had actually started working on but barely ran out of time implementing was another randomization for the planets. In addition to randomizing population, survivability, aesthetics, size, etc. I was also wanting to randomly generate a name for each planet. The script didn’t function as intended. Any modifications I made to the script caused bizarre errors where certain variables weren’t being passed into the object calling the script and, at one point, all consonants being absent.
After the jam completed I sat back down and refocused on making name generation work. Eventually I gave up on that script and decided to set up a standard ds_list that I would manually enter a massive list (150+ names) for the planets to select from. I have an object that handles generating ds_lists for reference at the start of the main room and also destroying those when that room ends. The code that specifically handles name generation is:
Global.nameList = ds_list_create();
Scr_name_list();
Ds_list_shuffle(global.nameList);
Global.namePos = -1;
The script scr_name_list simply has a massive list of names using ds_list_add(nameList,”name”);. Now that the script and ds_list are set up we simply add a few lines into the script already used for generating everything else for the planets. Those lines are:
Global.namePos++;
Var listSize = ds_list_size(global.nameList);
If global.namePos >  listSize {
               Global.namePos = 0;
}
Name = ds_list_find_value(global.nameList,global.namePos);
Pretty straight forward. Obviously this system isn’t what I initially anticipated for the Jam I’m happy with it because of the sheer amount of names that can be included with minimal work.
So am I happy with the initial version of One Small World? Yes and no. The parts I am happy with are things that, even as I write this, I smile about. I love the randomization scripts that I put together, especially when I look at some of my first attempts at this from when I first started making games. I also really love the look of the solar systems. I want to maybe add a few more options to planet randomization but, regardless, I have caught myself several times just enjoying the look of planets.
While few and far between the things I am not happy with are things that I extremely hate and also, in my opinion, bring down the rest of the game. I wish I had time to work out my own scripts for the processes I wanted rather than taking the easy route of using and modifying other people’s work. I wish I had thought of adding modifier indicators for when you do an action to a planet. I also REALLY hate how badly I messed up the design of the terraforming mechanic. That is my major miss and has taught me to look at mechanics from multiple perspectives.
The best part of this entire article is the negatives and wish list have already been fixed and/or added to v1.1 of the game which will be released when voting for Ludem Dare 38 ends (May 17th 2017). Be sure to check out the game here if you want to play/ vote!
Follow us on Twitter and check out our itch.io page!! 
0 notes
tetristar-interactive · 8 years ago
Text
Echo Systems in Gamemaker
Have you ever been working on a project and realized there was a minor adjustment that could have been made to make the entire piece feel more alive? I recently went through that while working on the upcoming A Most Shadowed Descent and The Order of Chains. In this instance I had been working on the sounds and wanted to test out an echo system for certain areas. I could have taken the easy route and simply added another piece of sound code but I wanted something that was more manageable and easier to implement.
Note: This will relate specifically to Gamemaker: 1.4 and may not be applicable to other coding languages/versions of Gamemaker.
Tumblr media
In scouring online, I couldn’t find anything that directly met my needs so I created a small system that will read whatever sound is playing and output a similar sound. The method I’m using not only can help with sound systems but is also a way to read a string and output the name of that string so it can be referenced.
Let’s start the process by creating a script:
scr_alarm_select
var echo = obj_sound_echo;
var time = room_speed/2;
 if echo.alarm[0] <= -1 {
   echo.alarm[0] = time;
   echo.alarm0_0 = argument0;
   echo.alarm0_1 = argument1;
} else if echo.alarm[1] <= -1 {
   echo.alarm[1] = time;
   echo.alarm1_0 = argument0;
   echo.alarm1_1 = argument1;
} else if echo.alarm[2] <= -1 {
   echo.alarm[2] = time;
   echo.alarm2_0 = argument0;
   echo.alarm2_1 = argument1;
} else if echo.alarm[3] <= -1 {
   echo.alarm[3] = time;
   echo.alarm3_0 = argument0;
   echo.alarm3_1 = argument1;
} else if echo.alarm[4] <= -1 {
   echo.alarm[4] = time;
   echo.alarm4_0 = argument0;
   echo.alarm4_1 = argument1;
} else if echo.alarm[5] <= -1 {
   echo.alarm[5] = time;
   echo.alarm5_0 = argument0;
   echo.alarm5_1 = argument1;
} else if echo.alarm[6] <= -1 {
   echo.alarm[6] = time;
   echo.alarm6_0 = argument0;
   echo.alarm6_1 = argument1;
} else if echo.alarm[7] <= -1 {
   echo.alarm[7] = time;
   echo.alarm7_0 = argument0;
   echo.alarm7_1 = argument1;
} else if echo.alarm[8] <= -1 {
   echo.alarm[8] = time;
   echo.alarm8_0 = argument0;
   echo.alarm8_1 = argument1;
} else if echo.alarm[9] <= -1 {
   echo.alarm[9] = time;
   echo.alarm9_0 = argument0;
   echo.alarm9_1 = argument1;
} else if echo.alarm[10] <= -1 {
   echo.alarm[10] = time;
   echo.alarm10_0 = argument0;
   echo.alarm10_1 = argument1;
} else if echo.alarm[11] <= -1 {
   echo.alarm[11] = time;
   echo.alarm11_0 = argument0;
   echo.alarm11_1 = argument1;
}
What we are doing with this is we are running an alarm whenever we need to echo. While not the most clean it is incredibly important because this determines how long the echo takes to start. We use the time variable to determine how long that pause is and the script proceeds to check if an alarm is already in use. Once it finds a free alarm it will set a specific variable to whatever arguments have been passed into it (we’ll go over this in a bit);
Next we’ll create the object we previously referenced called obj_sound_echo and put the following code into the Create Event:
obj_sound_echo (Create Event)
alarm0_0 = 0;
alarm0_1 = 0;
alarm1_0 = 0;
alarm1_1 = 0;
alarm2_0 = 0;
alarm2_1 = 0;
alarm3_0 = 0;
alarm3_1 = 0;
alarm4_0 = 0;
alarm4_1 = 0;
alarm5_0 = 0;
alarm5_1 = 0;
alarm6_0 = 0;
alarm6_1 = 0;
alarm7_0 = 0;
alarm7_1 = 0;
alarm8_0 = 0;
alarm8_1 = 0;
alarm9_0 = 0;
alarm9_1 = 0;
alarm10_0 = 0;
alarm10_1 = 0;
alarm11_0 = 0;
alarm11_1 = 0;
Tumblr media
Wow that’s a lot of variables. We’ll discuss what these are all used for in a bit but, for now we need to create 11 Alarms (the maximum Gamemaker: Studio 1.4 will allow us). Within each of these alarms we will add the following code:
obj_sound_echo (Alarms)
Scr_sound_echo(alarmx_0,alarmx_1);
Alarmx_0 = 0;*
Alarmx_1 = 0;*
*X denotes the alarm number (if within alarm5 the code will be “alarm5_0”)
In order to fully understand what’s going on we now need to add the script call line to our sound code which is placed wherever your sound is playing from:
Sound Code
If !audio_is_playing(snd_footstep) {
               Audio_play_sound(snd_footstep,1,false);
               Scr_alarm_select(snd_footstep,false);
}
With this we are starting to see how everything comes together. When we play our sound we run the scr_alarm_select script and pass in two arguments, the first being the sound we want to echo and the second being whether it loops. When we run scr_alarm_select it cycles through available alarms and then runs our last script:
scr_sound_echo
var soundname = audio_get_name(argument0);
var soundfull = soundname + string('_echo');
var soundfile = asset_get_index(soundfull);
var loop = argument1;
var gain = audio_sound_get_gain(argument0)/2;
 audio_play_sound(soundfile,1.5,loop);
audio_sound_gain(soundfile,gain,0);
In this script we take the arguments that have been passed from our initial code (Sound Code) and do some interesting things. For argument0 we get the name of the audio file using audio_get_name, store it in a variable called soundname and then create a variable called soundfull. We make this equal to soundname and then add string(‘_echo’);
Normally you can’t pass a string into a reference point for use in standard code. In order to change a string to a reference we use asset_get_index which will give the unique index for the new sound file which we can use.
Tumblr media
*Please note: the sound file that this outputs will be different from the one we passed in. In this instance we need to create a new sound file called snd_footstep_echo, otherwise the script will not function as intended.
The other thing this script does is determine if the echo sound should loop and also determines the volume of the echo. We do this by getting the gain of the initial sound file and simply dividing it by whatever number we decide.
The best part of using these scripts is, after implementation, if you want an echo effect just add the Scr_alarm_select(snd_footstep,false); line next to sound files that are normally playing. For the sake of full disclosure, I elected to not use this system in A Most Shadowed Descent and The Order of Chains simply because I decided to go a different direction. That said, the system works just as intended and could be very beneficial for those strapped for time with their projects.
Follow us on Twitter and check out our itch.io page!!
1 note · View note
tetristar-interactive · 8 years ago
Text
GML Speech Synthesis
As we are completing both The Order of Chains and A Most Shadowed Descent we have become determined to polish as many aspects as possible. One of the things we wanted to have was some form of speech that occurred. Reading large amounts of text in silence has a tendency to bore people. We worked for some time to determine how best to accomplish this and would like to show how we accomplished this.
Note: This will relate specifically to Gamemaker: 1.4 and may not be applicable to other coding languages/versions of Gamemaker. 
youtube
Step 1. Sound File Length
How the sounds are set up is completely up to you, but we created two separate sound files based on the different people that can be spoken to. We set their total lengths to .157 seconds with silence until .049 second at which point a beep plays for .060 seconds.
Tumblr media
Step 2. Creating Conversation Object
All dialogue for both games is ran by a single object that we will call obj_speechbubble. We will set up the object with the following code in the Create Event:
image_speed = 0; alarm[1] = 1; pitch = 1; speechcount = 0;
In addition to this we will use three images for our sprite:
Tumblr media Tumblr media Tumblr media
Next let’s set up Alarm[1]:
switch(image_index) {   case 0:       speechcount = 16;       break;   case 1:       speechcount = 11;       break;   case 2:       speechcount = 16;       break;
}
...Let’s talk about what’s going on here. In another object we have it set so the image index of our object is determined by who the character is. For example if we speak with a cultist it may set image_index = 2 while examining a knife would set image_index = 0;
This small alarm is ran and sets our speechcount variable that we will talk about shortly. The thing we will note is the specific number we assign is equal to the number of syllables in each bubble.
Now let’s fill in our Step Event:
if speechcount > 0 {   if image_alpha > 0 {       if image_index <= 1 {           if !audio_is_playing(snd_femalevoice) {               speechcount --;               audio_play_sound(snd_femalevoice,1,false);               scr_speech(snd_femalevoice,.75,1.25,false);               pitch = audio_sound_get_pitch(snd_femalevoice);           }       } else {           if !audio_is_playing(snd_malevoice) {               speechcount --;               audio_play_sound(snd_malevoice,1,false);               scr_speech(snd_malevoice,.75,1.25,true);               pitch = audio_sound_get_pitch(snd_malevoice);           }       }   } }
We created the obj_speechbubble and immediately set speechcount to a number. With the Step Event running each step it checks to see if the bubble is visible and then checks what image is showing. Remember, we determined the image index based on who was speaking so it stand to reason that we would have a separate voice.
We then subtract 1 from speechcount, play a sound, and run a script, in which we pass in four arguments.
Tumblr media
Step 3. scr_speech
Our next step is to create our speech script. It’s a pretty simple piece of code so it will be easy to dissect:
var target = argument0; var minrange = argument1; var maxrange = argument2; var cutoff = argument3;
if (pitch >= minrange) && (pitch <= maxrange) {   if speechcount > 1 {           var targetpitch = pitch + random_range(-.25,.25);   } else {       if cutoff = false {           var targetpitch = pitch + random_range(-.25,.25);       } else {           var targetpitch = pitch -.25;       }   } } else {   if speechcount > 1 {           var targetpitch = 1;   } else {       if cutoff = false {           var targetpitch = 1;       } else {           if pitch > minrange {               var targetpitch = pitch -.25;           } else {               var targetpitch = pitch;           }       }   } }
audio_sound_pitch(target,targetpitch);
Let’s start by talking about the arguments we just passed in.
Tumblr media
Argument0 [target] = the sound we are affecting
Argument1 [minrange] = the lowest pitch change we want
Argument2 [maxrange] = the highest pitch change we want
Argument3 [cutoff] = determines if bubble is the end of a sentence
Within the script we check if the pitch (which we should remember when the object is first created is set to 1) is at the lowest or highest range we want it. If that is okay and our speechcount variable is greater than 1 the script sets a new variable called targetpitch and sets that to the current pitch with a variance of a random range tacked onto the pitch.
If speechcount is 0 the script checks to see whether argument3 is false. If it’s false it means the sentence is not done and will continue to adjust the pitch as before. If the sentence is over and argument3 is true the pitch will be lowered.
Tumblr media
The reason this is done is because when we are finished with a sentence the pitch of our voice usually drops (see above image). This signals to those around us that we are finished with our thought and are now allowing feedback. Having the script determine if someone will be finishing a sentence creates a nice effect that helps make the random beeps to be translated into something more palatable.
The rest of the script says if the pitch is as low as it can be to keep pitch where it is (so as not to go below our minimum threshold), changes the pitch of our current sound, and then sets the pitch variable to what the current pitch is. If we didn’t set this variable each time the pitch wouldn’t adjust itself like normal speech does and would sound more like a computer.
Follow us on Twitter and check out our itch.io page!!
0 notes
tetristar-interactive · 8 years ago
Text
GML Seed Script without Recursion
We are currently in the polishing stages for our next releases A Most Shadowed Descent and The Order of Chains. While polishing the former of the two we came across an interesting situation that we wanted to discuss.
Note: This will relate specifically to Gamemaker: 1.4 and may not be applicable to other coding languages/versions of Gamemaker.
Tumblr media
A Most Shadowed Descent is a rogue-lite in that rather than being comprised of 100% procedural generation the game has 3 main areas and 6 seeds. These seeds yield determine in what order certain collectibles and items will spawn.
Version 1
When we started this process we had a simple piece of code handling our seed generation. We simply ran a script within the Create Event of a persistent object called obj_global_count.
randomize();
global.seed = choose(1,2,3,4,5,6);
This worked just fine for what we needed, but I’m sure you can already tell there was going to be a problem. The situation that arose from this was we wanted to ensure those playing the game got a chance to see every seed before having to replay a seed. This current line doesn’t differentiate from previous numbers at all.
Version 2
A problem we have with resolving situations is we tend to try to power our way through a problem rather than thinking about the situation properly. This has been no more evident than with our second version of the seed selection script.
Where previously we had the above lines of code we replaced with 6 variables (titled seed1-seed6 respectively) as well as calling the script scr_seed_select.
Here is our second attempt at the code. We have had to store it in this fashion because, as I’m sure you will have seen by opening the link, there are 859 lines of code.
Tumblr media
This is an obvious problem as it becomes near impossible to debug and comprehend in a timely fashion. So we moved on.
Version 3
We messed around with a few ideas at this point but eventually got frustrated. At that time we submitted this post on Reddit asking for help with our situation. A lovely person by the username of Ashlykos submitted a possible solution using ds_lists.
We had experimented with ds_lists for this situation but were having difficulty with storage of the variables because we wanted to ensure if someone exited and reloaded the game they wouldn’t get the same seed over and over.
So we tested. Where we previously had the 6 variables as well as the script caller we replaced with the following:
seed_list = ds_list_create(); if ds_list_size(seed_list) = 0 {     ds_list_add(seed_list,1,2,3,4,5,6);     randomize();     ds_list_shuffle(seed_list); }
global.seednum = 0;
From here, elsewhere in our game, we call the script from before (scr_seed_select) so it runs the following script which is a replacement of the 859 line script from before:
global.seednum++;
// Use a seed if global.seednum <= 6 {    global.seed = ds_list_find_value(obj_global_count.seed_list, global.seednum-1); } else {    global.seednum = 1;    randomize();    ds_list_shuffle(obj_global_count.seed_list);    global.seed = ds_list_find_value(obj_global_count.seed_list, global.seednum-1); }
Tumblr media
13 lines of code is much easier to manage. In addition to this we have three variables being saved and loaded (global.seed, global.seednum, and seed_list). Now, for those curious, let’s talk about what’s going in this script to explain the differences.
The Explanation
When the game starts for the first time it creates a ds_list titled seed_list. It then adds the numbers 1-6 to the list if they are not already present. This line specifically is to ensure the game still runs as intended on the first play through.
When the scr_seed_select script is ran is takes the global variable global.seednum and adds 1 to it. You may notice that in the create event we establish that global.seednum equals 0. When we add 1 to this when the script is initially ran and then use the ds_list_find_value code we notice we actually miss the first position on the list every single time. We attempted to have global.seednum equal to -1 to counteract this but for whatever reason Gamemaker determines that if it equals -1 it is undefined and will kick back and error. This is why we run our ds_list_find_value code at reading global.seednum-1 and set global.seed to this new number.
The second part of this uses global.seednum to determine if we have read every variable on the list. If global.seednum has been incremented 6 times the code resets it to 1 (because we’re subtracting when we locate values), reshuffles the list, and then sets global.seed to the new first position on this brand new list.
Tumblr media
Hopefully this provides a little insight into how we accomplished this task!
Follow us on Twitter
0 notes
tetristar-interactive · 8 years ago
Text
2017 Updates: 2 New Games!!
Hey there, It's been a while. We've been working on two games that are both within a single story. 
Tumblr media
In A Most Shadowed Descent you find your friend to be horribly disfigured. He tells you the only way to save him is by gathering mysterious objects from the nearby library. In this rogue-lite lovecraftian adventure game you must find clues in the world to determine what runes will save your friend, what runes will disfigure you, and what runes will destroy our reality.
Tumblr media Tumblr media
The Order of Chains is a mini-prequel that tells the story of how the friend came to be in his current state. Changing the pace via adding Point-and-Click-esque elements and having a greater emphasis on who the Cult we are dealing with is.
Tumblr media
Both of these games are in their final stages and will be released on PC within the next little bit. Until then, make sure you follow our Twitter page so you get updates on a more consistent basis.
Keep a look out for an upcoming article on the level design concepts used while designing this game. Have fun!!!
0 notes
tetristar-interactive · 9 years ago
Link
In preparation for an announcement this saturday we are selling The Grand Peratrur Nation for FREE!!! Check it out!!!
1 note · View note
tetristar-interactive · 9 years ago
Photo
Tumblr media
The Grand Peratrur Nation  is available today!! Buy it at https://tetristar-interactive.itch.io/the-grand-peratrur-nation!!!
0 notes
tetristar-interactive · 9 years ago
Text
A New Project and Mechanics
Well with The Grand Peratrur Nation nearing release on May 24th I am finally able to give into that creative bug that has been biting me for the last few months. For the next project that I will be making I wanted it to have an emotionally meaningful theme for someone I dearly love. My goal was to design a game that my son could go back and play years from now and realize just how much I care about him. 
Even after coming up with some of the main concepts and designing the main player ideas were still flowing in. Some of them were fantastic and really changed my vision for how the game would feel and play. Others though didn’t add anything to improve the game as I envisioned it. So today, I’d like to discuss one of these ideas and explain why it has now been cut from the project. 
Tumblr media
The game, which is still untitled, functions based on rooms. As of now each room you go to has a divergent path which will either increase or decrease the difficulty based on how you proceed. Some of the divergent rooms will have more or harder enemies while others will be safe areas where the player can rest, take in the environment, and learn more about the story. These were going to be the areas where most of the story would be divulged. 
The first idea was the game would keep track of how many times the player had been hit and how many times the player had hit an enemy. Each hit against the player would lower a morale counter and each hit against an enemy would raise the morale. When the player beat the final enemy the game would look at their morale and change the ending based on this count; a higher morale would yield a happier ending while a lower morale presents the opposite. 
Tumblr media
I had actually spent a good amount of time (compared to the time already spent on this project), on this idea. I had worked out what all of the different endings would comprise of. I figured out prematurely how many points would get you to what levels based on the enemies already designed. I even designed extra movements and attacks based around the player’s morale to give a more current view of what the player’s morale was. 
While in the throngs of designing this mechanic and getting extremely excited about how it would play out I took a step back and made a critical examination of what I was working on. I realized I had completely screwed up. I hadn’t screwed up in a design manner or even a mechanic sense. I had messed with the theme of my game and, were I to release my game with this morale mechanic, it would have been less effective as the media I wished it to be. 
Tumblr media
As we discussed I want this project to have meaning to my son. While multiple endings can still make for a meaningful experience to people it did not convey the emotion that I was looking for. My intent for the ending, as you all will see eventually, is for a mildly depressing setup with a strong optimistic view. The specific circumstances of this ending require a molding of the scenario. So while I will definitely use the work I have already put into it, I’ll not be using this mechanic in my next project. 
I think that’s what we all need to take into account when we are creating a system or a mechanic. Does it fit in with your theme and, if not, why? If it doesn’t fit in are you able to change it to fit your theme? Too many games nowadays will add in multiple mechanics that do nothing to help the theme of the game and, as such, suffer greatly from its addition.
Tumblr media
0 notes
tetristar-interactive · 9 years ago
Text
Grid Based Movement in Gamemaker
It’s no secret that one learns quite a bit about any field from practice. This is something that I have seen most prominently with coding. I started working on The Grand Peratrur Nation a few days before New Years Eve 2015 but didn’t start working on the code until a week or two into 2016. Since that time the code for the movement engine changed in a major way twice, the most recent being just yesterday. With this, I would like to discuss the major changes in this code for learning purposes.
(it should be noted we will only discuss the movement engine change from v2 to v3)
The Grand Peratrur Nation was always designed to have grid based movement. While a lot of initial tests were good, none had the exact feel I was looking for. The second version of the movement engine was inspired heavily from a tutorial I found from a small Youtube streamer (I honestly can’t find them again). With this engine it relied on the player object and all enemy objects having the following code in their Create event:
is_moving = false; move_speed = 1; grid_size = 20; move_timer = 0; speedx = 0; speedy = 0;
Let’s explain what these do:
is_moving = false; - determines if object is moving
move_speed = 1; - speed that object moves
grid_size = 20; - the size of square the object moves around
move_timer = 0; - a timer counting down showing movement
speedx = 0; - variable for horizontal movement
speedy = 0; - variable for vertical movement
For those of you who are upset with some of this code it’s okay, I feel your pain. These variables were referenced within the movement code for the object. To do this, I used a simple State-Based Machine (if you have questions on this there are PLENTY of tutorials online). The initial state was a movement script. Let’s look at the code for this movement, specifically the enemy movement script:
//Movement if is_moving = false && distance_to_point(obj_player.x, obj_player .y) > 10 && obj_player .death = false{    //Check Where Player Is    if ( obj_player .x > x && obj_player .y = y) && (obj_grid.cells[x div  20 +1, y div 20] == 0) {            is_moving = true;            move_timer = grid_size;            speedx = move_speed;            speedy = 0;    } else if ( obj_player .x < x && obj_player .y = y) && (obj_grid.cells[x div  20 -1, y div 20] == 0)  {            is_moving = true;            move_timer = grid_size;            speedx = -move_speed;            speedy = 0;    } else if ( obj_player .y < y && obj_player .x = x) && (obj_grid.cells[x div  20, y div 20 -1] == 0) {            is_moving = true ;            move_timer = grid_size;            speedy = -move_speed;            speedx = 0;    } else if ( obj_player .y > y && obj_player .x = x) && (obj_grid.cells[x div  20, y div 20 +1] == 0) {            is_moving = true;            move_timer = grid_size;            speedy = move_speed;            speedx = 0;    //Check Diagonals    } else if ( obj_player .x > x && obj_player .y > y) {        if (( obj_player .x-x > obj_player .y-y)) && (obj_grid.cells[x div  20 +1, y div 20] == 0) {                    is_moving = true;                    move_timer = grid_size;                    speedx = move_speed;                    speedy = 0;        }  else if (obj_grid.cells[x div  20, y div 20 +1] == 0){                    is_moving = true;                    move_timer = grid_size;                    speedy = move_speed;                    speedx = 0;        }    } else if ( obj_player .x < x && obj_player .y > y) {        if ((x- obj_player .x > obj_player .y-y)) && (obj_grid.cells[x div  20 -1, y div 20] == 0) {                    is_moving = true;                    move_timer = grid_size;                    speedx = -move_speed;                    speedy = 0;        }  else if (obj_grid.cells[x div  20, y div 20 +1] == 0){                    is_moving = true;                    move_timer = grid_size;                    speedy = move_speed;                    speedx = 0;        }    } else if ( obj_player .x < x && obj_player .y < y) {        if ((x- obj_player .x > y- obj_player .y)) && (obj_grid.cells[x div  20 -1, y div 20] == 0) {                    is_moving = true;                    move_timer = grid_size;                    speedx = -move_speed;                    speedy = 0;        }   else if (obj_grid.cells[x div  20, y div 20 -1] == 0){                    is_moving = true;                    move_timer = grid_size;                    speedy = -move_speed;                    speedx = 0;                }    } else if ( obj_player .x > x && obj_player .y < y) {        if (( obj_player .x-x > y- obj_player .y)) && (obj_grid.cells[x div  20 +1, y div 20] == 0) {                    is_moving = true;                    move_timer = grid_size;                    speedx = move_speed;                    speedy = 0;        } else if (obj_grid.cells[x div  20, y div 20 -1] == 0){                    is_moving = true;                    move_timer = grid_size;                    speedy = -move_speed;                    speedx = 0;                }    } } //End Movement if is_moving  = true {    x += speedx;    y += speedy;    move_timer -= move_speed;    if move_timer == 0 {        is_moving = false;    } }
What a mess. What it does is check where the player is, sets is_moving to true, sets move_timer to the grid_size, and then sets speedx or speedy to the movement. There is SO much going on in here. It was a pretty taxing process for the compiler as it not only references all of those variables but also several other objects inside of that and specific variables in those objects (see obj_grid.cells[x div 20 + 1, y div 20] == 0).
The biggest problem though was it was a monster to maintain and debug. It was essentially a shot in the dark to figure out where errors were occurring. So, in order to create a more functional system, I removed all of the aforementioned variables in favor of a much more simply solution. We didn’t need any of the other variables and, in fact, were able to get the entire thing running from just the script. Here it is:
//Movement if place_snapped(20,20) && distance_to_point(obj_player.x, obj_player .y) > 15 && obj_player .death = false{    //Move Enemy        //Straight Movement        if obj_player .y < y && obj_player .x = x && place_free(x, y - 20){            vspeed = -1;            hspeed = 0;        } else if obj_player .y > y && obj_player .x = x && place_free(x, y + 20){            vspeed = 1;            hspeed = 0;        } else if obj_player .x > x && obj_player .y = y && place_free(x + 20, y){            hspeed = 1;            vspeed = 0;        } else if obj_player .x < x && obj_player .y = y && place_free(x - 20, y){            hspeed = -1;            vspeed = 0;        }        //Diagonal Movement        if obj_player .y < y && obj_player .x > x && place_free(x, y - 20) {            vspeed = -1;            hspeed = 0;        } else if obj_player .y < y && obj_player .x < x && place_free(x, y - 20) {            vspeed = -1;            hspeed = 0;        } else if obj_player .y > y && obj_player .x > x && place_free(x, y + 20) {            vspeed = 1;            hspeed = 0;        } else if obj_player .y > y && obj_player .x < x && place_free(x, y + 20) {            vspeed = 1;            hspeed = 0;        }    } //Collisions if (vspeed > 0) && (place_meeting(x,y + 5, obj_player ) || place_meeting(x,y+5,obj_enemy_parent) || place_meeting(x,y,obj_boundary)) {    vspeed = 0;    move_snap(20,20); } else if (vspeed < 0) && (place_meeting(x,y - 5, obj_player ) || place_meeting(x,y-5,obj_enemy_parent) || place_meeting(x,y,obj_boundary)) {    vspeed = 0;    move_snap(20,20); } else if (hspeed > 0) && (place_meeting(x + 15,y, obj_player ) || place_meeting(x +15,y,obj_enemy_parent) || place_meeting(x+5,y,obj_boundary)) {    hspeed = 0;    move_snap(20,20); } else if (hspeed < 0) && (place_meeting(x - 15,y, obj_player ) || place_meeting(x -15,y,obj_enemy_parent) || place_meeting(x-5,y,obj_boundary)) {    hspeed = 0;    move_snap(20,20); }
Nothing fancy, but for enemy movement it doesn’t need to be. It functions in exactly the same way as the previous script; checking where the player is and then moving the object towards the player. The big difference though is it uses the built-in variables that GameMaker provides. The problem this presented was in the use of place_free. I was forced to go through all player and enemy objects and realign their collision boxes and ensure they were marked as solid. After this was done, though, it solved a problem I’ve had since Day 1 of enemies running into each other.
The point to all of this is something I have already mentioned in the past but bears repeating. If there is something that you do not like in your game and you are having difficulty figuring out a solution, take a step back and work on something else. Even if you don’t solve the issue immediately eventually you will be able to find a solution. Keep working on the skills required for that task and eventually you will have a deeper understanding of the parameters needed to succeed.
1 note · View note
tetristar-interactive · 9 years ago
Text
Slowly But Surely
The worst part about making a game during your down-time is if you don’t have any spare time to give to your project absolutely nothing gets done. This is what happened this last week. We experienced a few set backs not due to the project or home issues but rather commitments to our full-time jobs. 
Tumblr media
That being said, when we were finally able to get back to work on the game we made some major strides. The longest parts of working on the first two levels were coding in all the dialogue for the tutorials and ensuring the coding for the option to skip tutorials worked fine. Once we moved past those two levels, however, work progressed extremely quickly.
We finished the third level’s cut scenes in one day but remembered we had skipped past a major bug. In the interest of time we had left in that enemies would be able to run on top of each other so we wouldn’t spend days fixing it. We’ve all probably experienced that project that we can’t figure out, step away from, and then are able to fix it within a short amount of time. 
This is exactly what happened in this case. We were able to fix that bug within a few hours and, more importantly, we didn’t waste the extra time we would have spent on it when we initially noticed the problem. So, for our game design lesson of the day, don’t get hung up on a project. If you need to, just move on temporarily to get your mind off of the issue and then look at it with a new light.
Tumblr media
Either way, now that all of that is out of the way we are going to keep trucking through the cut scenes. If we stick to the schedule we’re on right now then we will be able to move to the next phase of the project (sound design) and then it’s all a matter of minor bug fixes, the trailer, and then shipping the game. We can’t wait for all of you to play The Grand Peratrur Nation!!
1 note · View note