Page 1 of 1

Basic NPC functions

Posted: Mon Mar 15, 2021 8:31 pm
by TheRetroRoomRoo
Hey everyone, Thank you for including me into the community! I am grateful to be here! I am not sure if this is the right place to be asking about stuff but I am on DSGM 5.12 and I wanted to see if I could get a little bit of help with a few things I am trying to create. I successfully built my an overworld using an RPG template. I put characters in that world that can speak and trigger certain variables.

I am curious if there is a system written for NPC random movement that also will also have the NPC characters be stopped as the main player is with the collision maps. I create a similar system in Gamemaker studio 2 using a random number to pick directions as well as distance, animate those characters, and have it loop while also checking for collisions... But id like to implement a similar system here.

I am also curious about creating collisions on those moving characters to stop the player from bumping into the characters. I know these are simple and fundamental techniques, but I am certain it will help me further my education in development for the DS using code. I am referring to the PAlib wiki for reference (https://sites.google.com/site/palibwiki/home) ....Thanks for your time and hopefully this thread can help others create these functions as well.

Re: Basic NPC functions

Posted: Tue Mar 16, 2021 2:34 am
by DigitalDesignDude
Welcome to the community TheRetroRoomRoo :)

Though there isn't a specific dedicated system written for random NPC movement in DSGM you can make your own with a combination of the following functions/code. You can find these functions and more from the DSGM code documentation.

DSGM Coding Documentation Post:
viewtopic.php?f=14&t=40

Code: Select all

If Test_Chance(k) 
'where 1 in every k times (randomly) the code will run.
End if

NpcDirection = Random(0, 3); 
'Set the NPC's direction is set to one of 4 directions randomly.


Set_Alarm(AlarmID, Time)
'where AlarmID is any ID number from 0-31 and Time is the number of frames you wish to wait before the alarm rings. 


if (Alarms[AlarmID].Rang) {
'When the Alarm rings, run whatever code you want.
'Then remember to reset the alarm ring to false for reuse.
 Alarms[AlarmID].Rang = false;
}

'Basic Timer Code
'Create a global integer called Counter in the game settings

If (Counter < AmountOfTime){
Counter++;
}

If (Counter > AmountOfTime){
'Run the Desired Code and then reset the Counter
Counter = 0;
}


If !Sprite_Collision(InstanceID1, InstanceID2)
'if the above object Ids are not colliding, then proceed with NPC movement code
}


If !Object_Under_Point(Screen, X, Y, "ObjectName")
If there's no object under a specific point, then proceed with NPC movement code
}

I have an example below I made years ago when I was learning DSGM that you can check out as well to see how I did my Random NPC movement and Collision. The basic random movement and collision code is as followed:

NPCs Random Movement & Talk Example
https://digitaldesigndude.itch.io/ds-ga ... r-examples

Code: Select all

'If npc is facing direction 0 (Right), is not collided with the player, other objects, nor the collision map, then move NPC in 1 in every 2 chances randomly per game update frame.

If Direction == 0 
if !Sprite_Collision([Me], Get_Single_ID(Player))
If !Object_Under_Point(Top_Screen, [X]+[Width]+2, [Y] + [Height]/2, "OtherObjectName")
if(PA_EasyBgGetPixelCol(Top_Screen, 3,[X] + [Width]+2, [Y] + [Height]/2)!= PA_RGB(0,0, 0)){
if Test_Chance(2)
[X]+= 2; 
End if 
End if
End if  

'In 1 in every 100 chances choose a random NPC direction
if Test_Chance(100)
  Direction=Random(0, 3); 
End if 

Re: Basic NPC functions

Posted: Tue Mar 16, 2021 5:25 am
by TheRetroRoomRoo
Thanks so much DigitalDesignDude, I have some studying to do to get comfortable with these functions. really appreciate you taking the time to message back! I see the power of DS Game Maker and I definitely love it so far. I am glad to be apart of the community. I hope to soon be able to contribute a little more than just questions ahaha but unfortunately I am definitely still a beginner. Does there happen to be a group discord as well?

Re: Basic NPC functions

Posted: Tue Mar 16, 2021 7:47 am
by Ruffsta
Does there happen to be a group discord as weel?
no, I don't have the time to run one.. However, I do give permission to DDD to start and run one if he so chooses to do so at some point..

Re: Basic NPC functions

Posted: Tue Mar 16, 2021 8:43 am
by DigitalDesignDude
TheRetroRoomRoo wrote: Tue Mar 16, 2021 5:25 am Thanks so much DigitalDesignDude, I have some studying to do to get comfortable with these functions... Does there happen to be a group discord as well?
Glad to help you get started @TheRetroRoomRoo, I gave you a lot of functions all at once so I hope it's not too overwhelming. I recommend staying away from DSGM's Built in Timer action (Set_Alarm) and to just use the Test_Chance() function to keep things simple when you start out.

Do ask if you need more clarification on anything as well. I try to answer questions the best I can when I'm able to do so.

Ruffsta wrote: Tue Mar 16, 2021 7:47 am
no, I don't have the time to run one.. However, I do give permission to DDD to start and run one if he so chooses to do so at some point..
As for a potential Discord Server, I can't make any promises, but I have been gaining more experience with running a Discord Server through my job and I may be able to help run one depending on my availability and the demand for one in the future.

For now I hope we can focus on building up the community and content available here on the forum. I am also open to live text chatting with others on Discord so if reasonable feel free to DM me at DDesignDude#0055.

Re: Basic NPC functions

Posted: Tue Mar 16, 2021 8:28 pm
by TheRetroRoomRoo
Thanks so much for the help, as a new developer, I would like to break some of these concepts down a little further so I can fully understand them. In the code example sent above, what is considered global variables and what is considered functions? Lets say my player object is called "Player1" and my Npc character object is called "NPC1"...If its not too much trouble could you show me notes of what is going on in the context of what is a function VS what is a Global Variable...also which languages are we using here? It is definitely new to me not to use brackets of some sort on conditionals like an "IF" statement. I hope these questions make sense hahah I suppose I just would like to see a further breakdown of some of these more fundamental concepts.

Re: Basic NPC functions

Posted: Wed Mar 17, 2021 3:09 am
by DigitalDesignDude
@TheRetroRoomRoo sure I can break things down for you.
TheRetroRoomRoo wrote: Tue Mar 16, 2021 8:28 pm also which languages are we using here? It is definitely new to me not to use brackets of some sort on conditionals like an "IF" statement.
First, let me go over the two languages DSGM 5.12 allows which is C and DSGM's own language called "DBAS".

In the below example code I provided you, I used a mix of the two languages because DSGM allows you to use them interchangeably but I should have just used 1 language to make things simpler for you. Sorry for the confusion.

Code: Select all

'If npc is facing direction 0 (Right), is not collided with the player, other objects, nor the collision map, then move NPC in 1 in every 2 chances randomly per game update frame.

If Direction == 0 
if !Sprite_Collision([Me], Get_Single_ID(Player1))
If !Object_Under_Point(Top_Screen, [X]+[Width]+2, [Y] + [Height]/2, NPC1)
if(PA_EasyBgGetPixelCol(Top_Screen, 3,[X] + [Width]+2, [Y] + [Height]/2)!= PA_RGB(0,0, 0)){
if Test_Chance(2)
[X]+= 2; 
End if 
End if
End if
End if
End if  

'In 1 in every 100 chances choose a random NPC direction
if Test_Chance(100)
  Direction=Random(0, 3); 
End if 
The difference between C and DBAS is basically DBAS is a simplified version of C where you don't need brackets or symbols like semicolons which makes it overall a simpler and more beginner-friendly language to read. Though it's ideal to only use 1 language (preferably C) there are some cases where you may have to use both languages in order for DSGM to read no errors and compile your game. DSGM can sometimes be very fussy for the littlest mistakes such as extra spaces in the code.

Below is the same code now entirely written with C. However you may have errors if you try to run the same code as I didn't test it.

Code: Select all

//If npc is facing direction 0 (Right), is not collided with the player, other objects, nor the collision map, then move NPC in 1 in every 2 chances randomly per game update frame.

if (Direction == 0){ 
if !(Sprite_Collision([Me], Get_Single_ID(Player1))){
if !(Object_Under_Point(Top_Screen, [X]+[Width]+2, [Y] + [Height]/2, NPC1)){
if (PA_EasyBgGetPixelCol(Top_Screen, 3,[X] + [Width]+2, [Y] + [Height]/2)!= PA_RGB(0,0, 0)){
if (Test_Chance(2)){
[X] += 2; 
}
}
} 
}
}

//In 1 in every 100 chances choose a random NPC direction
if (Test_Chance(100)){
  Direction = Random(0, 3); 
} 


TheRetroRoomRoo wrote: Tue Mar 16, 2021 8:28 pm In the code example sent above, what is considered global variables and what is considered functions? Lets say my player object is called "Player1" and my Npc character object is called "NPC1"...If its not too much trouble could you show me notes of what is going on in the context of what is a function VS what is a Global Variables.
Now let me explain the global variables and functions used in the above code.

Code: Select all

if (Direction == 0){ 
Direction is a global integer variable I made which is responsible for keeping track of which direction the NPC is facing. Integers variables have an integer-based value, meaning they can only be equal to whole numbers as opposed to Float variables which allow for numbers with decimals. Note that you can declare global variables in the tools menu or in an external .h file. In this example, I have decided that when Direction = 0, then the NPC is facing right and that the movement code will only run when the NPC is facing right.

Code: Select all

if !(Sprite_Collision([Me], Get_Single_ID(Player1))){
Here I'm using the function Sprite_Collision(InstanceID1, InstanceID2) where we check to see if the NPC has collided with the player. If NOT, then continue running the rest of the code that follows. In coding, a function is just premade code that carries out a certain task for you without you needing to write all the directions yourself. If we were not to use the Sprite_Collision Function, we would then have to use many 'if' statements to check to see if the x and y coordinates of the two game objects are overlapping. Why re-create code that's already been created for you and many others to use right? That's the purpose of DSGM's built-in functions.

Code: Select all

if !(Object_Under_Point(Top_Screen, [X]+[Width]+2, [Y] + [Height]/2, NPC1)){
Now we use the Object_Under_Point(Screen, Xposition, Yposition, ObjectName) function to check to see if any other instances (i.e duplicates) of NPC1 are going to be in the way of NPC1's movement. Assuming the game takes place on the Nintendo DS's top screen we have specified as such in the "Screen" parameter of the function. The Xposition is just the current x position of our moving NPC1 (i.e [X]) plus its sprite width and 2 pixels. We add this offset from [X] because our NPC is going to be moving right by 2 pixels in this example and so we need to check if the space 2px to the right of our NPC1 is unoccupied. The sprite width is added because in DSGM the position of a game object is actually measured from the very top left corner of a sprite. So you always need to add offset numbers when dealing with sprite positions to get accurate results. The Yposition is just the vertical midpoint of the sprite (i.e [Y] + half the sprite's height). Also, note that the y-axis in DSGM is more positive as you go down and more negative as you go up in the game world. That's backwards from what you learned in elementary school, I know.

Code: Select all

if (PA_EasyBgGetPixelCol(Top_Screen, 3,[X] + [Width]+2, [Y] + [Height]/2)!= PA_RGB(0,0, 0)){
Next, we check if our NPC is going to collide with the collision map with the PA_EasyBgGetPixelCol(Screen, BackgroundLayer, Xposition, Yposition) function. This function returns (i.e gives us) the pixel's color in RGB values from the position and background layer we specify. Just like the Object_Under_Point function we check to see if the NPC has NOT collided with the collision map by checking the pixel that is 2 pixels to the right of the NPC's very edge and is vertically in the middle of the NPC. So long as the pixel's color isn't black (i.e 0,0,0) then proceed with the next line of code.

Code: Select all

if (Test_Chance(2)){
In this example, the Test_Chance(sides) function is being used to randomize the movement of the NPC. In this case, every time the game updates/refreshes its frame there's a one in 2 chance of the NPC being able to move. This causes the NPC to have a stutter-like movement so you may want to use a combination of randomized timers instead to get NPC movement that's more commonly found in RPG games.

Code: Select all

[X] += 2; 
If all the above conditions are met, then the NPC can finally move exactly 2 pixels to right every time the game refreshes/updates. (DSGM games has a frame/refresh rate of 60 frames per second).

Code: Select all

if (Test_Chance(100)){
  Direction = Random(0, 3); 
} 
Lastly, we set the NPC to randomly change its direction whenever the Test_Chance function returns true. I felt a 1 in every 100 chance was appropriate for this example.

That's the breakdown of the code that I used for random NPC movement. I only provided what you need for the NPC to move in the RIGHT direction, but you should have everything you need to allow the NPC to move in the other 3 possible directions (left, up, down). You basically reuse the same code 3 more times except with different values for the x and y movement and position values.