Author Topic: Keyboard input and Do loops  (Read 10434 times)

dutch_619

  • Regular
  • **
  • Posts: 90
    • View Profile
    • Email
Keyboard input and Do loops
« on: 2007-02-20, 08:47:44 PM »
I have two questions. The first is pretty easy

To begin I wanted to set the script to fire 4 bullets for every key press. I nested a loop,( i=4 while i >= 0 do, etc. but I think there's an easier way to do this. I get an odd error on occasion while loading the game and I think the script is the culprit. I think If I have the runtime component sleep before running It would run smoother and disregard any spurious input while loading. It would be simpler to use the extant counter in the script and dump my added on bits.

My next question involves grabbing the keyboard inputs for the playable sprite. I am using the BMDX to do this now, but the trouble is it grabs all playable sprites, even in instances I want the thing to be inert. I was hoping to grab the keyboard inputs without having to define collisions and solidity in the script. Any suggestions?

Thanks.

bluemonkmn

  • SGDK Author
  • Administrator
  • Fanatic
  • *****
  • Posts: 2761
    • ICQ Messenger - 2678251
    • MSN Messenger - BlueMonkMN@gmail.com
    • View Profile
    • http://sgdk2.sf.net/
    • Email
Re: Keyboard input and Do loops
« Reply #1 on: 2007-02-20, 09:15:32 PM »
I don't understand your questions -- BMDXCtls doesn't know anything about sprites so I don't know what you mean by BMDXCtls "grabbing sprites".  And if you want to perform a loop more simply, use a For loop (For I = 1 to 4), but this isn't much simpler that using a while loop and a variable, and probably wouldn't have any effect on whatever error you're getting.  I can't guess what the problem is without knowing the error.

dutch_619

  • Regular
  • **
  • Posts: 90
    • View Profile
    • Email
Re: Keyboard input and Do loops
« Reply #2 on: 2007-02-20, 10:10:22 PM »
I believe I have a handle on the first error, so that one can be disregarded.

The problem I have is that in order to make the playable sprite act the way I want I'm using events from the display object. I'm having trouble specifying the sprite I want to be affected by this. For the load screen I use an inert sprite and special functions to move it and interact with it. When using the aforementioned display events it will move the inert menu sprite as well as the playable sprite.

What I am attempting to do is to give the playable sprite a steady default speed in the direction it is facing. I then want to use the up and down keys to affect velocity, so that it moves faster while the up key is held and slower while the down is held. I am currently scrabbling for an simple way to do this. I have a few ideas but I would like to avoid the complexities I see in my ideas.

bluemonkmn

  • SGDK Author
  • Administrator
  • Fanatic
  • *****
  • Posts: 2761
    • ICQ Messenger - 2678251
    • MSN Messenger - BlueMonkMN@gmail.com
    • View Profile
    • http://sgdk2.sf.net/
    • Email
Re: Keyboard input and Do loops
« Reply #3 on: 2007-02-21, 07:26:36 AM »
It sounds like you need help distinguishing when to affect the sprite or which sprite to affect.  What part of that are you having trouble with?  Can you just check the sprite definition name associated with the sprite to see if it's one that you want to affect?

dutch_619

  • Regular
  • **
  • Posts: 90
    • View Profile
    • Email
Re: Keyboard input and Do loops
« Reply #4 on: 2007-02-21, 11:53:11 PM »
Hmm... I want to affect the playable sprite in all the various maps except the menu and credits map. I'd like to avoid having redundant pieces of code for the same sprite in various guises on different maps. The effect I want to have is, as before, to set the sprite to move at a set speed forward in whichever direction it is pointing. Then I'd like to use the up/down keys to either increase or decrease its speed. I can get this to work by having the up and down keys remapped in the gdp. file, then setting the up key to work when an arbitrarily picked key is not pressed. I then use the up and down keys to change to a new sprite thats either faster or slower. This is a very ugly way of doing so.

I have also tried setting the sprite to inert and doing the same thing with scripting and sinking keypresses to increase or decrease the sprites maximum speed.

I finally tried editing the source code to do this as well, but it leads to the unpleasant prospect of having a project that no one else can edit as it has to be deployed with an installer.

What I really could use at this point is an easier way to do these things. I am fortunately quickly becoming acquainted with VB which is an un-looked for boon. I do dislike how variables are used in VB. It seems untidy.

bluemonkmn

  • SGDK Author
  • Administrator
  • Fanatic
  • *****
  • Posts: 2761
    • ICQ Messenger - 2678251
    • MSN Messenger - BlueMonkMN@gmail.com
    • View Profile
    • http://sgdk2.sf.net/
    • Email
Re: Keyboard input and Do loops
« Reply #5 on: 2007-02-22, 06:41:05 AM »
1) You don't need to sink events of the display to trap player input.  You can use the Player_OnControllerMoved event and/or bits from ProjectObj.GamePlayer.CtlActions  (I think the scripting reference in the help file documents the values of different bits that can be in this property as "Enum eActionBits").

2) Can you keep your same code, but just add a condition to skip it when you're on the menu?  For example:
Code: [Select]
If ProjectObj.GamePlayer.rMap.Name = "Menu" Then Exit Sub

dutch_619

  • Regular
  • **
  • Posts: 90
    • View Profile
    • Email
Re: Keyboard input and Do loops
« Reply #6 on: 2007-02-22, 08:45:23 PM »
I think I see how to do this in C script, but not in VB. Like so I assume for C...

Void getinput()
{

    if (key[KEY_ESC])      gameover = 1;
    if (key[KEY_UP])        forward(1);
    if (key[KEY_RIGHT])   turnright(1);
    if (key[KEY_LEFT])     turnleft(1);
    if (key[KEY_DOWN])   backward(1);
}

void forward(int num)
{
    if (key_count[num]++ > key_delay[num])
    {
        key_count[num] = 0;

        player[num]->xspeed++;
        if (player[num]->xspeed > MAXSPEED)
            player[num]->xspeed = MAXSPEED;
    }
}

etc. etc. etc.
« Last Edit: 2007-02-22, 08:48:24 PM by dutch_619 »

bluemonkmn

  • SGDK Author
  • Administrator
  • Fanatic
  • *****
  • Posts: 2761
    • ICQ Messenger - 2678251
    • MSN Messenger - BlueMonkMN@gmail.com
    • View Profile
    • http://sgdk2.sf.net/
    • Email
Re: Keyboard input and Do loops
« Reply #7 on: 2007-02-23, 06:17:09 AM »
Do you just want me to translate that into VB script?
Code: [Select]
Sub getinput()
   If key(KEY_ESC) Then gameover = 1
   If key(KEY_UP) Then forward 1
   If key(KEY_RIGHT) Then turnright 1
   If key(KEY_LEFT) Then turnleft 1
   If key(KEY_DOWN) Then backward 1
End Sub

Sub forward(num)
   If key_count(num) > key_delay(num) Then
      key_count(num) = 0
      player(num).xspeed = player(num).xspeed + 1
      If player(num).xspeed > MAXSPEED Then
         player(num).xspeed = MAXSPEED
      End If
   Else
      key_count(num) = key_count(num) + 1
   End If
End Sub

dutch_619

  • Regular
  • **
  • Posts: 90
    • View Profile
    • Email
Re: Keyboard input and Do loops
« Reply #8 on: 2007-02-23, 09:11:21 PM »
Thats not too different from C code. I guess I just need to know how to reference my sprite from the code. I'd like to pull as much info from the sprite definition as I can, rather than coding it into the script.

I think it's something like this

.....shooting script......

Sub Player_OnPlayInit()
   HostObj.StartScript=1
End Sub

HostObj.SinkObjectEvents ProjectObj.GamePlayer, "Player"
HostObj.ConnectEventsNow()
ProjectObj.GamePlayer.Play 16

#Split ========== Gameplay script (Number 1) ========


Option Explicit


Dim oPlayer

Set oPlayer = NewGameDevObj("Player")
Sub Player_OnPlayInit

 
Sub getinput()
   If key(KEY_UP) Then forward 1
   If key(KEY_RIGHT) Then turnright 1
   If key(KEY_LEFT) Then turnleft 1
   If key(KEY_DOWN) Then backward 1
End Sub

Sub forward(num)
   If key_count(num) > key_delay(num) Then
      key_count(num) = 0
      player(num).xspeed = player(num).xspeed + 1
      If player(num).xspeed > MAXSPEED Then
         player(num).xspeed = MAXSPEED
      End If
   Else
      key_count(num) = key_count(num) + 1
   End If
End Sub

Sub turnright(num)
   If key_count(num) > key_delay(num) Then
      key_count(num) = 0
      player(num).yspeed = player(num).yspeed + 1
      If player(num).yspeed > MAXSPEED Then
         player(num).yspeed = MAXSPEED
      End If
   Else
      key_count(num) = key_count(num) + 1
   End If
End Sub

Sub turnleft(num)
   If key_count(num) > key_delay(num) Then
      key_count(num) = 0
      player(num).yspeed = player(num).yspeed + 1
      If player(num).yspeed > MAXSPEED Then
         player(num).yspeed = MAXSPEED
      End If
   Else
      key_count(num) = key_count(num) + 1
   End If
End Sub     

Sub backward(num)
   If key_count(num) > key_delay(num) Then
      key_count(num) = 0
      player(num).xspeed = player(num).xspeed + 1
      If player(num).xspeed > MAXSPEED Then
         player(num).xspeed = MAXSPEED
      End If
   Else
      key_count(num) = key_count(num) + 1
   End If
End Sub



HostObj.SinkObjectEvents ProjectObj.GamePlayer, "Player"
HostObj.SinkObjectEvents CurrentDisplay, "Display"

HostObj.ConnectEventsNow()





bluemonkmn

  • SGDK Author
  • Administrator
  • Fanatic
  • *****
  • Posts: 2761
    • ICQ Messenger - 2678251
    • MSN Messenger - BlueMonkMN@gmail.com
    • View Profile
    • http://sgdk2.sf.net/
    • Email
Re: Keyboard input and Do loops
« Reply #9 on: 2007-02-24, 08:11:45 AM »
1) You can access the sprite that the project defines as the current player sprite for the current map with: ProjectObj.GamePlayer.PlayerSprite.  The properties and methods of PlayerSprite are listed under the definition "Sprite Object" in the scripting reference.  From there you can also access the sprite's definition (which includes the name) and template.  DX and DY are the speed of the sprite and are right on the Sprite Object.

2)  If you want to enumerate other sprites on the player sprite's layer, you can use:
Code: [Select]
Dim Idx, Player2
Set Player2 = Nothing
With ProjectObj.GamePlayer.PlayerSprite.rDef.rLayer
   For Idx = 0 To .SpriteCount - 1
      If .Sprite(Idx).rDef.Name = "Player2" Then Set Player2 = .Sprite(Idx)
   Next
End With
That example shows how you could look through all the sprites in the layer to find one whose definition is named "Player2".  If it finds one, it stored it in a variable called Player2 which you can then use directly.  If you want to check if any Player2 sprite was found, you can use:
If Player2 Is Nothing Then ' Player 2 doesn't exist

3) You don't need to maintain a key() array to track what keys the player is pressing.  The player object does that for you.  If you want to see if the default player is pressing up:
If (ProjectObj.GamePlayer.CtlActions And 1) <> 0 Then ' Player is pressing up
Did you see the 2-player demo project?

dutch_619

  • Regular
  • **
  • Posts: 90
    • View Profile
    • Email
Re: Keyboard input and Do loops
« Reply #10 on: 2007-02-24, 06:42:42 PM »
I've been using the "GoldYoink" and the 2 player demo as references for how SGDK handles Vb scripting. I keep trying to do things as I would in C++ and it tends to louse things up.

The up side is that I now have a semi-functional script for my game. As soon as I add some functionality and another level or two I think I'll be done. Thanks for the help, it's been appreciated.

dutch_619

  • Regular
  • **
  • Posts: 90
    • View Profile
    • Email
Re: Keyboard input and Do loops
« Reply #11 on: 2007-03-13, 08:02:47 AM »
Still having problems with my script.

Here's what I'm trying at present

Code: [Select]
Sub Player_OnControllerMove(OldActions, NewActions)
If (Not OldActions) And NewActions And ACTION_UP Then DoSpriteAccelerate
                If (Not OldActions) And NewActions And ACTION_DOWN  Then DoSpriteDeccelerate
                If Not (Not OldActions) And (Not NewActions) And ACTION_DOWN Then DoSpriteSteady
                If Not (Not OldActions) And (Not NewActions) And ACTION_UP Then DoSpriteSteady

End Sub

Sub DoSpriteAccelerate
Dim DX, DY, oPlayerSprite
Set oPlayerSprite = ProjectObj.GamePlayer.PlayerSprite
 With ProjectObj.GamePlayer.PlayerSprite
oPlayerSprite.X =.X + (.Width -oPlayerSprite.Width)/2
oPlayerSprite.Y =.Y + (.Width -oPlayerSprite.Width)/2
   GetStateDeltas DX, DY
oPlayerSprite.DX = (DX * oPlayerSprite.rDef.Template.MoveSpeed) * 1.2
oPlayerSprite.DY = (DY * oPlayerSprite.rDef.Template.MoveSpeed) * 1.2
If oPlayerSprite.rDef.Template.StateCount = 36 Then oPlayerSprite.CurState = RectToPolarState(DX, DY)
 End With
End Sub


Sub DoSpriteDeccelerate
Dim DX, DY, oPlayerSprite
Set oPlayerSprite = ProjectObj.GamePlayer.PlayerSprite
 With ProjectObj.GamePlayer.PlayerSprite
oPlayerSprite.X =.X + (.Width -oPlayerSprite.Width)/2
oPlayerSprite.Y =.Y + (.Width -oPlayerSprite.Width)/2
   GetStateDeltas DX, DY
oPlayerSprite.DX = (DX * oPlayerSprite.rDef.Template.MoveSpeed) * .8
oPlayerSprite.DY = (DY * oPlayerSprite.rDef.Template.MoveSpeed) * .8
If oPlayerSprite.rDef.Template.StateCount = 36 Then oPlayerSprite.CurState = RectToPolarState(DX, DY)
 End With
End Sub


Sub DoSpriteSteady
Dim DX, DY, oPlayerSprite 
Set oPlayerSprite = ProjectObj.GamePlayer.PlayerSprite
 With ProjectObj.GamePlayer.PlayerSprite
'oPlayerSprite.X =.X + (.Width -oPlayerSprite.Width)/2
'oPlayerSprite.Y =.Y + (.Width -oPlayerSprite.Width)/2
   GetStateDeltas DX, DY
oPlayerSprite.DX = (DX * oPlayerSprite.rDef.Template.MoveSpeed)
oPlayerSprite.DY = (DY * oPlayerSprite.rDef.Template.MoveSpeed)
If oPlayerSprite.rDef.Template.StateCount = 36 Then oPlayerSprite.CurState = RectToPolarState(DX, DY)
 End With
End Sub


Function GetStateDeltas(DX, DY)
With ProjectObj.GamePlayer.PlayerSprite
Select Case .rDef.Template.StateType
Case STATE_SINGLE
If Abs(DX) + Abs(DY) > 1 Then
DX = .DX / (Abs(.DX) + Abs(.DY))
DY = .DY / (Abs(.DX) + Abs(.DY))
Else
If Abs(DX) + Abs(DY) < 1 Then DX = 0 : DY = -1
End If
Case STATE_LEFT_RIGHT
DY = 0
If (.CurState Mod 2) = 0 Then DX = -1 Else DX = 1
Case STATE_8_DIRECTION
Select Case (.CurState Mod 8)
Case 0 : DX = 0 : DY = -1
Case 1 : DX = 1 : DY = -1
Case 2 : DX = 1 : DY = 0
Case 3 : DX = 1 : DY = 1
Case 4 : DX = 0 : DY = 1
Case 5 : DX = -1 : DY = 1
Case 6 : DX = -1 : DY = 0
Case 7 : DX = -1 : DY = -1
End Select
Case Else
DX = Cos((.CurState Mod 36) * 3.14159 / 18)
DY = -Sin((.CurState Mod 36) * 3.14159 / 18)
End Select
End With
End Function


Function RectToPolarState(X, Y)
Dim Angle, Pi
Pi = 3.14159
If X <> 0 Then
Angle = Atn(-Y / X)
Else
Angle = -(Pi / 2) * Sgn(Y)
End If
If X < 0 Then
Angle = Pi + Angle
ElseIf Y > 0 Then
Angle = Pi * 2 + Angle
End If
RectToPolarState = ((Angle * 18) / Pi) Mod 36
End Function





HostObj.SinkObjectEvents ProjectObj.GamePlayer, "Player"
HostObj.ConnectEventsNow()
ProjectObj.GamePlayer.Play 16






Unfortunately I can't think of an easy way to adjust the direction of the sprite. I think maybe call a Function with an added value to the angle variable in a custom based off of the Function used in the script wizard. I know this a terribly ugly way to code this, but I still have trouble with how Gamedev interacts with the sprite definitions.

dutch_619

  • Regular
  • **
  • Posts: 90
    • View Profile
    • Email
Re: Keyboard input and Do loops
« Reply #12 on: 2007-03-13, 04:55:57 PM »
I added this to handle the key config, and it works, but the player sprite is inert so it doesn't know how to handle the keyleft or keyright keypresses.

Code: [Select]
Sub Player_OnPlayInit
   With ProjectObj.GamePlayer
KeyUp = 38
KeyLeft = 37
KeyRight = 39
KeyDown = 40
KeyBtn1 = 17
KeyBtn2 = 32
KeyBtn3 = 16
KeyBtn4 = 13
End With
End Sub



Hmm, maybe I should just call a special function that changes the sprite templates maxspeed when keyup or keydown are pressed. Then I can leave the sprite controlled by the input device.

I still need to add some code that calls the template modifying code only when the sprite is one of a certain group of names.

bluemonkmn

  • SGDK Author
  • Administrator
  • Fanatic
  • *****
  • Posts: 2761
    • ICQ Messenger - 2678251
    • MSN Messenger - BlueMonkMN@gmail.com
    • View Profile
    • http://sgdk2.sf.net/
    • Email
Re: Keyboard input and Do loops
« Reply #13 on: 2007-03-13, 05:03:18 PM »
All you need to do to set the direction of the sprite is set the CurState property to a number from 0 to 35.  The number represents the angle in degrees divided by 10.  So if you want the sprite to point right, set CurState to 0.  If you want it to point up, set it to 9, etc.

dutch_619

  • Regular
  • **
  • Posts: 90
    • View Profile
    • Email
Re: Keyboard input and Do loops
« Reply #14 on: 2007-03-13, 05:16:41 PM »
Hmm so I pull the sprite state and increment or decrement it.

something like this
Code: [Select]
Sub DoSpriteTurnLeft
Dim oPlayerSprite, nStateInt
Set oPlayerSprite = ProjectObj.GamePlayer.PlayerSprite
With ProjectObj.GamePlayer.PlayerSprite
     Let oPlayerSprite.CurState = nStateInt
          If nStateInt = 0 Then
               Set PlayerSprite.CurState = 35
          If nStateInt > 0 Then
               Set PlayerSprite.CurState = nStateInt - 1
End With
End Sub


Sub DoSpriteTurnRight
Dim oPlayerSprite, nStateInt
Set oPlayerSprite = ProjectObj.GamePlayer.PlayerSprite
With ProjectObj.GamePlayer.PlayerSprite
     Let oPlayerSprite.CurState = nStateInt
          If nStateInt = 35 Then
               Set PlayerSprite.CurState = 0
          If nStateInt < 35 Then
               Set PlayerSprite.CurState = nStateInt + 1
End With
End Sub
End Sub
« Last Edit: 2007-03-13, 05:53:05 PM by dutch_619 »