How to make code panel?

Started by pietrek, Mon 02/06/2014 12:22:08

Previous topic - Next topic

pietrek

Hi.

How can I make working code panel (example code: 7145, 8411 etc.). If I choose correct code I'll leave room, if incorrect -  won't do anything.

Sth like this:


monkey0506

Pretty much the easiest way to do it would be to:

*) Create a global String variable (say, "sPanelPassword")
*) Whenever you show the GUI or enter the room where this panel is shown, set your String to empty (e.g., sPanelPassword = "";)
*) Whenever you click on one of the numerical buttons, append it to the String (e.g., sPanelPassword = sPanelPassword.AppendChar('1');)
*) Now, check it against the correct password (e.g., sPanelPassword.EndsWith("7145"))
*) If it's the wrong password but the correct number of digits have been entered (check sPanelPassword.Length), you can reset the String back to empty and display a "Wrong Password" message

monkey424

An alternative method:

I'd use a GUI with buttons for the key pad.

In your script, declare an array with 4 elements.

e.g.

int A[4];

(gives you: A[0], A[1], A[2], A[3])

Note that you don't have to use arrays, but I like them.

You need to assign code to each button to record it's value when clicked (i.e. store value in the last array element A[3]).

You also need to store the values of the last few buttons clicked (using the other array elements, in descending order).

Suggest this code:

// click on button

A[0] = A[1];

A[1] = A[2];

A[2] = A[3];

A[3] = value of last button pressed;

So when you press the four buttons in the correct order, the array variables will reflect this.

e.g.

press 8 9 3 5

will give A[0] = 8,  A[1] = 9,  A[2] = 3,  A[3] = 5
    

monkey0506

It's arguing semantics, but using four separate slots in an array is more complicated, and error-prone, than using a single String. The String method allows you to compare the result once against a single string-literal, whereas you are suggesting to check the value of four separate slots.

You're not wrong, and the array approach is actually significantly more memory efficient. *shrugs* Whichever is easiest for the end user I suppose. ;)

Gurok

#4
Ignore arrays v/s strings and memory efficiency, monkey_05_06. They actually behave slightly differently. Consider the situation where the passcode is 7145 and the user enters 37145. As I understand it, yours will reset the string after 3714 and at the end, the string will contain 5. monkey424's will tolerate 3714 and at the end, the array will contain 7145. Remove that check in your pseudo code for "the correct number of digits" and the two suggestions should behave very similarly.
[img]http://7d4iqnx.gif;rWRLUuw.gi

EliasFrost

I have one of those in my game. The way I did it was as follows (not sure if it's the best way but it's working):

1) First I knew I needed a way to store all of the four digits, so I made four variables. (could also have used an array but we all do things differently) These variables are: nr1, nr2 etc.
2) I made another variable used to determine what position in the sequence you are currently entering, whether it's the first or the third etc. I called this 'int current'. This variable is (for the purpose of its use) ranged from 1 to 4. That is, the number of digits in the code. I set this to 1 when I defined it.
3) When you press a button, the script will first check 'current' to see what digit in the sequence you are currently placed at, if 'current' == 1, then I change the value of nr1 to whatever the number of the button were. Then I printed it onto a label with String.Format to show the number on a prompt. I then bumped 'current' + 1, so the next button press would then logically be checking 'current == 2'.
4) This repeats for all 4 digits, if it's false, set 'current = 1' and reset all the nr# variables to 0. If it's right, then do whatever is gonna happen when you get the right code.

Oh yeah and I simply compared the label.text with another string with the right code to check if it's true or not.

Khris

Or we could use invisible inventory items to store which button was pressed.

Just kidding, not sure why we're listing progressively worse methods of accomplishing this though.

EliasFrost

I guess I'm thw worst then? :(

Khris

Maybe not the worst, but certainly the most laborious. ;-D

monkey0506

Quote from: Gurok on Thu 05/06/2014 00:32:56yours will reset the string...Remove that check in your pseudo code for "the correct number of digits" and the two suggestions should behave very similarly.

Quote from: monkey_05_06 on Mon 02/06/2014 12:57:17you can reset the String

I listed "that check" as an optional step, not a mandatory one. Assuming that the check is omitted, then yes, the two give the same results (which was kind of my point in responding to 424).

For what it's worth, Elias' code is still essentially the same thing, we're just listing more and more complicated (and therefore potentially error-prone) means to the same end. 8-)

Gabarts

Interesting posts

Would be nice to add a randomizer for the code. Each time the game starts it mixes up the correct sequence for the hotspots or buttons...
is possible to do?

geork

Sure, just use a 'random' function and insert that into whatever method you choose. 'Random' gives you an integer number between

So for Monkey_05_06's, you could create a separate string called "password", and assign every value to a random number
Code: ags
String password = String.Format("%d%d%d%d", Random(9), Random(9), Random(9), Random(9));

then you would check the user input string with the 'password' string:
Code: ags
if(sPanelPassword.EndsWith(password)) //Success!


For Monkey424's method, I'd create another set of arrays, which we'll call 'B', then assign each to a random number. So:
Code: ags
int B[4];
//probably in game_start or something
B[0] = Random(9);
B[1] = Random(9);
B[2] = Random(9);
B[3] = Random(9);

Then to compare:
Code: ags
if(A[0] == B[0] && A[1] == B[1] && A[2] == B[2] && A[3] == B[3]) //Success!


So basically, use Random(int) to achieve the randomizer for the code.

Hope that helps! :)

Creator

#12
Quote from: Gabarts on Mon 09/06/2014 08:23:05
Interesting posts

Would be nice to add a randomizer for the code. Each time the game starts it mixes up the correct sequence for the hotspots or buttons...
is possible to do?

Definitely. Using monkey_05_6's method, wherever you set the password, just do this:

Code: ags

int ran = Random(2); //Gives you 3 random passwords. 0, 1 and 2.

if (ran == 0)
{
  sPanelPassword = "1234";
}
else if (ran == 1)
{
  sPanelPassword = "4321";
}
else if (ran == 2)
{
  sPanelPassword = "9876";
}


That's how I'd do it. Not sure if there's a simpler way.

EDIT - Damn. Ninja'd. gerok's would work with a 100% random code. Mine only does a pre defined set.

EDIR 2 - Oh. You'd have to have a second variable to compare sPanelPassword with for my method, so you'd have to modify monkey_05_06's method/code slightly to fit what I've suggested. For example:

Code: ags

/*Global strings:
sPanelPassword: What the password is set to.
sPanelPasswordEntry: What the numbers entered on the panel are.

Then to check the password: */
if (sPanelPassword == sPanelPasswordEntry)
{
  //whatever happens.
}

Gabarts

Ok for a code panel or numbers... the AppendChar seems the easiest function to apply for this.
But what about something like this, I may need it for my main Venice puzzle at the end.


monkey0506

You could just use the actual sprite slot numbers as the password key. Something like:

Angel Sprite: 72
Catapult Sprite: 43
Chimera Sprite: 115
Correct Password: 4311572

Angel x3 = 727272
Catapult-Chimera-Chimera = 43115115
Chimera-Angel-Chimera = 11572115

You could simply use:

Code: ags
sPassword.Append(String.Format("%d", clickedPanel.Graphic));


where clickedPanel is an Object* to whichever panel was most recently clicked on. This approach could be problematic if you have, say, a fourth sprite slot number 243, because then the sequence "24311572" would end with "4311572". So, you'd have to watch out for that caveat and maybe change some sprite numbers, but otherwise it's functionally the same.

Khris

The basic idea is to have an array of sprite slots and a variable for each mural:
Code: ags
// sprite slots of each mural, 0 = angel, 1 = catapult, etc., 6 total
#define murals 6
int mural_slots[murals];

enum Mural {
  eMuralAngel,
  eMuralCatapult,
  eMuralDragon,
  ...
};

// 0: left mural, 1: center mural, 2: right mural
int mural[3];

// in room_Load
  mural_slots[eMuralAngel] = 132; // angel sprite
  mural_slots[eMuralCatapult] = 133; // catapult sprite
  ...
  // set initial configuration
  mural[0] = eMuralAngel; // left mural is showing angel initially
  mural[1] = eMuralCatapult;
  mural[2] = eMuralDragon;

Now implement each mural as an Object.
Code: ags
function oLeftMural_Interact() {
  // walk to mural, etc.
  // advance to next mural
  mural[0] = (mural[0] + 1) % murals; // 6 wraps to 0
  // update object graphic
  oLeftMural.Graphic = mural_slots[mural[0]];
  // check for combination
  if (check_murals()) open_door();
}


The check is simple:
Code: ags
bool check_murals() {
  // combination: 
  return mural[0] == eMuralWhatever && mural[1] == eMuralGrail && mural[2] == eMuralDragon;
}

Gabarts

Fantastic :) You are a treasure of coding!

SMF spam blocked by CleanTalk