Scrolling Game Development Kit Forum
SGDK Version 2 => Help, Errors, FAQ => Topic started by: Tanja on 2007-11-07, 01:42:50 PM
-
in version 1 i found a box to be checked: Enable Joystick.
How do i the same with sgdk2?
first i thought i could change "SpriteBase.InputBits.Left" to another button, but it doesn't works.
-
This is done by the player at runtime. In the Options menu, the player can choose to use the keyboard or mouse. There is no change necessary in the project itself to have a sprite be controlled by either a keyboard or joystick.
-
ok. then i need to make a start screen with options and so on.
why does sgdk not recognizes if i press a key on keyboard or a button on my gamepad?
that's an extra move for the player which might isn't necessary. i find it a little uncomfortable.
-
I think this is an improvement of SGDK2 over version 1. Version 1 forces the game designer to choose what controls the player uses to play the game. Usually the player wants to be in control of that. You can change the default by editing the code in the SourceCode folder, or (I think) by setting the controls and saving the settings to a file (use the "IncludeInSaveUnit" function and the "SaveGame" function to save only the player settings) then using "LoadGame" to load the settings when the game starts. (IncludeInSaveUnit and SaveGame could be part of your project temporarily -- just long enough to create the save file after your settings are set up; then you can delete them from your project.)
-
i don't want to force some input device. what happens when i force gamepad and the user don't has one?
again, why does sgdk not recognizes if i press a key on keyboard or a button on my gamepad on (at?) runtime and deals with that input?
sure it`s an improvement that the player CAN choose.
-
You could add a new type of player (by implementing the IPlayer interface) that accepts input from both the keyboard and the joystick somewhat easily. Just look at Player.cs, which implements the two separately. Then look at this code in GameForm.cs:
Players[0] = new KeyboardPlayer(0);
// Players 1 through (M-N) use keyboard while players (M-N+1) through M use controllers
// where M is max player number and N is number of controllers.
for (int playerIdx = 1; playerIdx<Project.MaxPlayers; playerIdx++)
{
if ((controllers != null) && (Project.MaxPlayers - playerIdx <= controllers.Length))
Players[playerIdx] = new ControllerPlayer(playerIdx - (Project.MaxPlayers - controllers.Length));
else
Players[playerIdx] = new KeyboardPlayer(playerIdx);
}
which sets which players get which input types. I could see a player type that, upon the first input, sets itself to that type of input for the rest of the game. Something like:
[Serializable()]
public class EitherInputPlayer : KeyboardPlayer
{
public int deviceNumber;
public int[] buttonMap;
private GameForm gf;
private int index;
private int defaultSet;
public EitherInputPlayer(int deviceNumber, int defaultSet, GameForm gameForm, int myIndex)
{
base(defaultSet);
this.defaultSet = defaultSet;
this.deviceNumber = deviceNumber;
buttonMap = new int[4] {0, 1, 2, 3};
gf = gameForm;
index = myIndex;
}
public bool Up
{
get
{
return keyboard(Project.GameWindow.KeyboardState[key_up]) ||
controller(Project.GameWindow.GetControllerState(deviceNumber).Y < 0x4000);
}
}
public bool Left
{
get
{
return keyboard(Project.GameWindow.KeyboardState[key_left] ||
controller(Project.GameWindow.GetControllerState(deviceNumber).X < 0x4000);
}
}
public bool Right
{
get
{
return keyboard(Project.GameWindow.KeyboardState[key_right] ||
controller(Project.GameWindow.GetControllerState(deviceNumber).X > 0xC000);
}
}
public bool Down
{
get
{
return keyboard(Project.GameWindow.KeyboardState[key_down] ||
controller(Project.GameWindow.GetControllerState(deviceNumber).Y > 0xC000);
}
}
public bool Button1
{
get
{
return keyboard(Project.GameWindow.KeyboardState[key_button1] ||
controller(Project.GameWindow.GetControllerState(deviceNumber).GetButtons()[buttonMap[0]] != 0);
}
}
public bool Button2
{
get
{
return keyboard(Project.GameWindow.KeyboardState[key_button2] ||
controller(Project.GameWindow.GetControllerState(deviceNumber).GetButtons()[buttonMap[1]] != 0);
}
}
public bool Button3
{
get
{
return keyboard(Project.GameWindow.KeyboardState[key_button3] ||
controller(Project.GameWindow.GetControllerState(deviceNumber).GetButtons()[buttonMap[2]] != 0);
}
}
public bool Button4
{
get
{
return keyboard(Project.GameWindow.KeyboardState[key_button4] ||
controller(Project.GameWindow.GetControllerState(deviceNumber).GetButtons()[buttonMap[3]] != 0);
}
}
private bool keyboard(bool input)
{
if (input)
gf.Players[index] = new KeyboardPlayer(defaultSet);
return input;
}
private bool controller(bool input)
{
if (input)
gf.Players[index] = new ControllerPlayer(deviceNumber);
return input;
}
}
and change the first line of the section of code previously mentioned in GameForm.cs to:
if ((controllers != null) && (controllers.Length > 0))
Players[0] = new EitherInputPlayer(0,0,this,0);
else
Players[0] = new KeyboardPlayer(0);
This hasn't been tested, so I don't know if it'll work. But it's a general outline of how I'd go about it anyway.
-
woohoo! i'll try that! thanks!
-
tried it out now, but there are error messages.
one question in advance:
i am not sure if i did this right (change the first line of the section of code previously mentioned in GameForm.cs)
is it supposed to look like that?
// Player 0 always uses keyboard by default
if ((controllers != null) && (controllers.Length > 0))
Players[0] = new EitherInputPlayer(0,0,this,0);
else
Players[0] = new KeyboardPlayer(0);
// Players 1 through (M-N) use keyboard while players (M-N+1) through M use controllers
// where M is max player number and N is number of controllers.
for (int playerIdx = 1; playerIdx<Project.MaxPlayers; playerIdx++)
{
if ((controllers != null) && (Project.MaxPlayers - playerIdx <= controllers.Length))
Players[playerIdx] = new ControllerPlayer(playerIdx - (Project.MaxPlayers - controllers.Length));
else
Players[playerIdx] = new KeyboardPlayer(playerIdx);
}
the other code i have pasted in, but you didn't mention the place. i guess it doesn't matters anyway.
here are the errors:
meins2\Player.cs(35,16) : warning CS0108: The keyword new is required on 'EitherInputPlayer.Up' because it hides inherited member 'KeyboardPlayer.Up'
meins2\Player.cs(44,16) : warning CS0108: The keyword new is required on 'EitherInputPlayer.Left' because it hides inherited member 'KeyboardPlayer.Left'
meins2\Player.cs(53,16) : warning CS0108: The keyword new is required on 'EitherInputPlayer.Right' because it hides inherited member 'KeyboardPlayer.Right'
meins2\Player.cs(62,16) : warning CS0108: The keyword new is required on 'EitherInputPlayer.Down' because it hides inherited member 'KeyboardPlayer.Down'
meins2\Player.cs(71,16) : warning CS0108: The keyword new is required on 'EitherInputPlayer.Button1' because it hides inherited member 'KeyboardPlayer.Button1'
meins2\Player.cs(80,16) : warning CS0108: The keyword new is required on 'EitherInputPlayer.Button2' because it hides inherited member 'KeyboardPlayer.Button2'
meins2\Player.cs(89,16) : warning CS0108: The keyword new is required on 'EitherInputPlayer.Button3' because it hides inherited member 'KeyboardPlayer.Button3'
meins2\Player.cs(98,16) : warning CS0108: The keyword new is required on 'EitherInputPlayer.Button4' because it hides inherited member 'KeyboardPlayer.Button4'
meins2\Player.cs(25,11) : error CS1501: No overload for method 'KeyboardPlayer' takes '0' arguments
meins2\Player.cs(27,7) : error CS0175: Use of keyword base is not valid in this context
meins2\Player.cs(49,84) : error CS1026: ) expected
meins2\Player.cs(58,84) : error CS1026: ) expected
meins2\Player.cs(67,84) : error CS1026: ) expected
meins2\Player.cs(76,105) : error CS1026: ) expected
meins2\Player.cs(85,105) : error CS1026: ) expected
meins2\Player.cs(94,105) : error CS1026: ) expected
meins2\Player.cs(103,99) : error CS1026: ) expected
i will try to do something about it, but have little hope.
-
The change you made looks good in GameForm.cs
I fixed the errors in the code. I made sure it compiled this time. I've been programming in java lately, so I'm just a bit rusty. This should be correct. Pasting it at the bottom of Player.cs seems like a good place to put it, but it might also be a good idea to create it as its own separate code object, just in case you have to reset the code at some point for some reason. There's no getting around the fact that you'd have to change GameForm.cs if you reset the code, but that's a minimal change.
[Serializable()]
public class EitherInputPlayer : KeyboardPlayer
{
public int deviceNumber;
public int[] buttonMap;
private GameForm gf;
private int index;
private int defaultSet;
public EitherInputPlayer(int deviceNumber, int defaultSet, GameForm gameForm, int myIndex) : base(defaultSet)
{
this.defaultSet = defaultSet;
this.deviceNumber = deviceNumber;
buttonMap = new int[4] {0, 1, 2, 3};
gf = gameForm;
index = myIndex;
}
new public bool Up
{
get
{
return keyboard(Project.GameWindow.KeyboardState[key_up]) ||
controller(Project.GameWindow.GetControllerState(deviceNumber).Y < 0x4000);
}
}
new public bool Left
{
get
{
return keyboard(Project.GameWindow.KeyboardState[key_left]) ||
controller(Project.GameWindow.GetControllerState(deviceNumber).X < 0x4000);
}
}
new public bool Right
{
get
{
return keyboard(Project.GameWindow.KeyboardState[key_right]) ||
controller(Project.GameWindow.GetControllerState(deviceNumber).X > 0xC000);
}
}
new public bool Down
{
get
{
return keyboard(Project.GameWindow.KeyboardState[key_down]) ||
controller(Project.GameWindow.GetControllerState(deviceNumber).Y > 0xC000);
}
}
new public bool Button1
{
get
{
return keyboard(Project.GameWindow.KeyboardState[key_button1]) ||
controller(Project.GameWindow.GetControllerState(deviceNumber).GetButtons()[buttonMap[0]] != 0);
}
}
new public bool Button2
{
get
{
return keyboard(Project.GameWindow.KeyboardState[key_button2]) ||
controller(Project.GameWindow.GetControllerState(deviceNumber).GetButtons()[buttonMap[1]] != 0);
}
}
new public bool Button3
{
get
{
return keyboard(Project.GameWindow.KeyboardState[key_button3]) ||
controller(Project.GameWindow.GetControllerState(deviceNumber).GetButtons()[buttonMap[2]] != 0);
}
}
new public bool Button4
{
get
{
return keyboard(Project.GameWindow.KeyboardState[key_button4]) ||
controller(Project.GameWindow.GetControllerState(deviceNumber).GetButtons()[buttonMap[3]] != 0);
}
}
private bool keyboard(bool input)
{
if (input)
gf.Players[index] = new KeyboardPlayer(defaultSet);
return input;
}
private bool controller(bool input)
{
if (input)
gf.Players[index] = new ControllerPlayer(deviceNumber);
return input;
}
}
-
yes it compiles now. but the player type doesn't change automatically, it seems. when i create an .exe, i have to change to gamepad manually. any idea why it is how it is?
-
I'm not sure what you mean. Does it accept both types of input? When did you check to see if it's changed? The "Options" form will show that it's a keyboard player, because the EitherInputPlayer class inherits from the KeyboardPlayer, but it also implements code to interpret input from a controller. The first time the game checks for input (with something like MapPlayerToInputs) and gets a result (some button is pressed) it will use that type of controller from then on. Or it should anyway.
Please elaborate on the situation.
-
the game doesn't react to gamepad inputs, unless i change the input type to game controller. ( in the compiled game)
apropos, i have the problem after i changed to game controller, i can't switch back to keyboard. you see why when you look at the attachment.
in debug mode the game doesn't react to my gamepad at all. i could upload my game so can take a look into it.
-
Well, my main problem with testing is that I don't have a game controller to test with. Although that does look like a possible bug with the form design.
-
Well, my main problem with testing is that I don't have a game controller to test with.
well.... f***. ok, options will do it. (change to game controller).
with that window thing, maybe could bluemonkmn say something about that?
-
The problem with the sizing of the controller options dialog was fixed after the beta was released. You could fix it in your project pretty easily too:
- Open Controls.cs from the SourceCode folder in your project.
- Search for the first occurrence of "ClientSize". It should occur after a line that says "cboPlayer.Hide".
- At the end of the ClientSize line there is a number "185". Change it to 270.
That's it! Was that the only problem left relating to controllers, or was something else not working?
Hopefully I'll release a new beta version soon with a number of fixes.
-
thanks, it worked!
may i ask you what the "mn" means at the end of your nickname?
edit: it is not a real problem left, but the fact the player type durnurd wrote for me isn't working. do you have a gamepad to try it out?
-
1) The "MN" at the end of my name is a hint that I am from Minnesota.
2) If you upload your project to http://sgdk2.enigmadream.com/support (http://sgdk2.enigmadream.com/support) I'll take a look next time I get a chance. I have a joystick I could test it with.
-
I've tried this out as a more generalized approach. Rather than combining exactly one keyboard player and one controller player, it combines two IPlayer interfaces of any type, so I was able to test it with two keyboard inputs which worked. So the idea is that you initialize it by passing in the types of players you want to use, and it will figure it out from there.
The downside here is that the controller options dialog won't work until a specific controller type is selected by using it. So here's the player code:
[Serializable()]
public class AnyInputPlayer : IPlayer
{
private GameForm gf;
private int index;
private IPlayer pa;
private IPlayer pb;
public EitherInputPlayer(IPlayer p1, IPlayer p2, GameForm gameForm, int myIndex)
{
gf = gameForm;
index = myIndex;
pa = p1;
pb = p2;
}
new public bool Up
{
get
{
return a(pa.Up) || b(pb.Up);
}
}
new public bool Left
{
get
{
return a(pa.Left) || b(pb.Left);
}
}
new public bool Right
{
get
{
return a(pa.Right) || b(pb.Right);
}
}
new public bool Down
{
get
{
return a(pa.Down) || b(pb.Down);
}
}
new public bool Button1
{
get
{
return a(pa.Button1) || b(pb.Button1);
}
}
new public bool Button2
{
get
{
return a(pa.Button2) || b(pb.Button2);
}
}
new public bool Button3
{
get
{
return a(pa.Button3) || b(pb.Button3);
}
}
new public bool Button4
{
get
{
return a(pa.Button4) || b(pb.Button4);
}
}
private bool a(bool input)
{
if (input)
gf.Players[index] = pa;
return input;
}
private bool b(bool input)
{
if (input)
gf.Players[index] = pb;
return input;
}
}
and you'll have to make this change to Controls.cs:
if (Project.GameWindow.Players[SelectedPlayer] is KeyboardPlayer)
{
bLoading = true;
KeyboardPlayer player = (KeyboardPlayer)Project.GameWindow.Players[SelectedPlayer];
rdoKeyboard.Checked = true;
txtUp.Text = System.Enum.Format(typeof(Microsoft.DirectX.DirectInput.Key), player.key_up, "g");
txtLeft.Text = System.Enum.Format(typeof(Microsoft.DirectX.DirectInput.Key), player.key_left, "g");
txtRight.Text = System.Enum.Format(typeof(Microsoft.DirectX.DirectInput.Key), player.key_right, "g");
txtDown.Text = System.Enum.Format(typeof(Microsoft.DirectX.DirectInput.Key), player.key_down, "g");
txtButton1.Text = System.Enum.Format(typeof(Microsoft.DirectX.DirectInput.Key), player.key_button1, "g");
txtButton2.Text = System.Enum.Format(typeof(Microsoft.DirectX.DirectInput.Key), player.key_button2, "g");
txtButton3.Text = System.Enum.Format(typeof(Microsoft.DirectX.DirectInput.Key), player.key_button3, "g");
txtButton4.Text = System.Enum.Format(typeof(Microsoft.DirectX.DirectInput.Key), player.key_button4, "g");
bLoading = false;
}
else if (Project.GameWindow.Players[SelectedPlayer] is ControllerPlayer)
and this change to GameForm.cs:
if (controllers != null && controllers.Length > 0)
Players[0] = new EitherInputPlayer(new KeyboardPlayer(0), new ControllerPlayer(0), this, 0);
else
Players[0] = new KeyboardPlayer(0);
-
you could test it and it worked? strange, i get these errors:
meins4\Controls.cs(723,1) : error CS0116: A namespace does not directly contain members such as fields or methods
meins4\Controls.cs(723,48) : error CS1518: Expected class, delegate, enum, interface, or struct
meins4\Controls.cs(726,92) : error CS1518: Expected class, delegate, enum, interface, or struct
meins4\Controls.cs(737,7) : error CS1022: Type or namespace definition, or end-of-file expected
meins4\Player.cs(480,11) : error CS1520: Class, struct, or interface method must have a return type
and i resetted the three .cs files before, so code from the previous tries couldn't affect the new code.
maybe you could send me your three .cs files so i can copy them into my game?
oh, and could someone tell me how to create these code objects?
-
Did you paste the code for Controls.cs at the end of the file? Looks like there were no instructions on where to put it, but I think it should replace some similar-looking code on line 619 instead of just being added to the end of the file.
-
oh, you are right!
the errors for controls.cs are gone.
but this line remains:
meins4\Player.cs(480,11) : error CS1520: Class, struct, or interface method must have a return type
in the code, line 480 starts this way:
public EitherInputPlayer(IPlayer p1, IPlayer p2, GameForm gameForm, int myIndex)
{
gf = gameForm;
index = myIndex;
pa = p1;
pb = p2;
}
-
Whoops, I renamed the class without renaming the constructor. Just change EitherInputPlayer to AnyInputPlayer to fix that.
-
i'm sad.
it has been so many changes, maybe i lost the overview. could someone please do the changes and send me the three .cs files please?
-
Here's an SGDK2 file containing the code you'll need. Just import the three objects into the source code folder of your project.
http://www.findmyed.com/files/AnyInputPlayer.zip
-
man, i hate it. every thing that is step more advanced than the easiest thing, doesn't work here.
i imported the files into my actual game and my first version. the same error occured again. then i tried it with the sample project. it works there!
-
Try resetting the source code in your project and then import it again. Either I'm working off of a different version than the default or you are. I built it based on the sample project, so if that's different, that may be the problem, but I don't see why the any differences in that project would affect this problem.
Better yet, reset it to the code in the sample project. That would probably work best.
-
man, i hate it. every thing that is step more advanced than the easiest thing, doesn't work here.
i imported the files into my actual game and my first version. the same error occured again. then i tried it with the sample project. it works there!
You're welcome to keep at it and durnurd will probably get enough information to you that your project will work. But you should understand that you are writing code, which of course is a very sensitive thing. Even the smallest error in copying or writing code will cause fatal errors in your project. If you're not prepared to deal with these kinds of problems, you might want to avoid fiddling with the code, and just accept the built-in features as they are instead of getting into the coding. If you want to get into the coding, you should be prepared to take some time to study how coding works and do some trial and error to learn from the mistakes. Then you could work out many of these problems on your own. But it would take patience to learn how to write code. Viel Gluck! :)
-
as a c++ programmer myself, i know its fustrating. :( >:(
-
interest = yes
time = no
anyway i have to try...