Author Topic: Mouse Aiming/sthooting  (Read 23053 times)

durnurd

  • Lead Lemming
  • Expert
  • Fanatic
  • *****
  • Posts: 1234
  • Games completed so far: 0
    • MSN Messenger - durnurd@hotmail.com
    • View Profile
    • Find My Ed
Re: Mouse Aiming/sthooting
« Reply #15 on: 2006-02-08, 04:30:55 PM »
If sprites are destroyed though sprite collisions and special functions, then you could make a loop that will automatically find the index every time either of those things happens, something like this:

Code: [Select]
dim AimSpriteIdx
AimSpriteIdx = 14

Sub FindAim()
   with ProjectObj.GamePlayer
      dim sprCount
      sprCount = .rMap.MapLayer(0).SpriteCount
      for (i = 0 to sprCount - 1)
         if .rMap.MapLayer(0).Sprite(i).rDef.Name = "aim" then
            AimSpriteIdx = i
            exit for
         end if
      next
      if i = sprCount then            'Uhoh, we didn't find it!
         .bQuit = true                  'Quit gracefully.  Remove this line if you don't want it to quit and have an error instead.
         msgbox "Couldn't find the targeting reticle sprite!  Searched through " + sprCount + " sprites, but no luck."
      end if
   end with
End Sub

Sub Player_OnSpecialEvent(SpecialObj)
   FindAim()
End Sub

Sub Player_OnSpritesCollide(Name, ClsASprIdx, ClsBSprIdx, CollDefIdx)
   FindAim()
End Sub
Edward Dassmesser

ragingmime

  • Visitor
  • *
  • Posts: 11
    • View Profile
Re: Mouse Aiming/sthooting
« Reply #16 on: 2006-02-08, 07:20:21 PM »
Durnurd, you are my hero. Thanks a million.

There are still a few quirks (e.g. if you restart the level, you'll have to make sure to run FindAim again), but otherwise it works beautifully. I'm thinking about putting aim on its own layer, which should solve all the problems. (By the way, for anyone who wants to use the themselves, make sure to remove the parentheses on the line with the "for" or else GameDev will get angry).

I have crosshairs! Hooray!

durnurd

  • Lead Lemming
  • Expert
  • Fanatic
  • *****
  • Posts: 1234
  • Games completed so far: 0
    • MSN Messenger - durnurd@hotmail.com
    • View Profile
    • Find My Ed
Re: Mouse Aiming/sthooting
« Reply #17 on: 2006-02-08, 08:16:19 PM »
Oops, too much programming in Java and PHP for me :P

As for putting it on its own layer, how would that affect the shooting function?  How exactly do you "shoot" using the targeting reticle?  Does it create a sprite relative to the position of the "aim" sprite?  Is there a sprite collision between the "aim" sprite and enemy sprites?  If either of these is true, then the "aim" sprite has to be on the same layer as the other sprites, otherwise no collision is detected.

Also, If you just change the last two subs to this:

Code: [Select]
Sub Player_OnFrameStart(gameActive)
   FindAim()
End Sub

Then it will refind the targeting reticle every frame, which shouldn't cause a significant slow-down.  However, it's just cleaner only to update the index when required.  When you restart the level, does that use a special function?  Because that should run FindAim, but apparently not.  Also, some refinement could be made to the code, like not re-finding the sprite if it hasn't changed, but that wouldn't cause any improvement as far as the bugs are concerned, there's not a necessity to do so (but it would make it cleaner and possibly run faster on low-end systems).
Edward Dassmesser

ragingmime

  • Visitor
  • *
  • Posts: 11
    • View Profile
Re: Mouse Aiming/sthooting
« Reply #18 on: 2006-02-08, 09:47:18 PM »
I'm going to pass the x and y coordinates of the reticle to the shooting function. That function will use trigonometry and the x and y coordinates to determine the angle at which the projectile should be shot (i.e., angle = inverse tangent of y/x). So it does create a sprite (a bullet) relative to the "aim" sprite, but it only uses variables that have been defined within the script to do so.

The main reason that I want to put the "aim" sprite on its own layer is so that it won't scroll with the rest of the sprites. That way, it'll only move if the user moves the mouse. Will I take a performance hit for that?

Restarting the level uses a special function defined in the windowed map dialogue, not the full-screen editor. Maybe that's why OnSpecialEvent doesn't get triggered when I restart.

durnurd

  • Lead Lemming
  • Expert
  • Fanatic
  • *****
  • Posts: 1234
  • Games completed so far: 0
    • MSN Messenger - durnurd@hotmail.com
    • View Profile
    • Find My Ed
Re: Mouse Aiming/sthooting
« Reply #19 on: 2006-02-08, 11:23:09 PM »
Oh, I completely forgot.  Any special function you define that you want to re-find the sprite has to have the "Raise Event" flag checked (i.e. functions that delete sprites or functions that change the map).

As for the shooting function, it sounds like an effective solution if you take into account cartesian coordinates rather than vectors.  You wouldn't need an angle at all, really.  I assume that you have a player sprite on the screen that is doing the shooting towards the crosshairs?  So it would be something like

Code: [Select]
    With ProjectObj.GamePlayer
        cX = .rMap.MapLayer(0).Sprite(AimSpriteIdx).X    'Or, alternatively, this could just be cX = X and cY=Y if calling from a MouseDown event
        cY = .rMap.MapLayer(0).Sprite(AimSpriteIdx).Y    'This is assuming that the crosshairs is on a layer with a scrollrate of 0 in both directions
        pX = .PlayerSprite.X - .MapScrollX - .rMap.ViewLeft    'I'm not sure if this is entirely correct, but what I'm trying to do is get the distance the player
        pY = .PlayerSprite.Y - .MapScrollY - .rMap.ViewTop   'is from the edge of the screen, not the edge of the map, so that the distance to the crosshairs is correct
    End With
    Speed = 10                'Some constant speed (in Pixels per Frame)
    dx = cX - pX
    dy = cY - pY
    If dy = 0 Then
       SpeedX = Speed * sgn(dx)
       SpeedY = 0
    ElseIf dx = 0 Then
       SpeedX = 0
       SpeedY = Speed * sgn(dy)
    Else
        ratio = Abs(dx / dy)
        SpeedX = Abs(Speed / (1 + ratio)) * Sgn(dx)
        SpeedY = (Speed - Abs(SpeedX)) * Sgn(dy)
    End If
    'Now just get a bullet sprite and set its DX to SpeedX and its DY to SpeedY
« Last Edit: 2006-02-08, 11:32:29 PM by durnurd »
Edward Dassmesser

ragingmime

  • Visitor
  • *
  • Posts: 11
    • View Profile
Re: Mouse Aiming/sthooting
« Reply #20 on: 2006-02-11, 12:14:04 AM »
Thanks! I've edited your code to simplify it a little and to make it work within the shooting script:

Code: [Select]
Function GetStateDeltas(DX, DY)
     With ProjectObj.GamePlayer
        cX = .rMap.MapLayer(1).Sprite(AimSpriteIdx).X    'Or, alternatively, this could just be cX = X and cY=Y if calling from a MouseDown event
        cY = .rMap.MapLayer(1).Sprite(AimSpriteIdx).Y    'This is assuming that the crosshairs is on a layer with a scrollrate of 0 in both directions
        pX = .PlayerSprite.X - .MapScrollX - .rMap.ViewLeft    'I'm not sure if this is entirely correct, but what I'm trying to do is get the distance the player
        pY = .PlayerSprite.Y - .MapScrollY - .rMap.ViewTop   'is from the edge of the screen, not the edge of the map, so that the distance to the crosshairs is correct
    End With
    DistToReticleX = cX - pX
    DistToReticleY = cY - pY
    'calculate the hypotenuse of the triangle (the other sides being thedx and thedy) so that we can find the cosine and sine of the angle that's opposite to the hypotenuse - i.e. the angle between the player and the reticle. The hypotenuse, then, is the line between the player and the targeting reticle.
    hypot = sqr(DistToReticleX * DistToReticleX + DistToReticleY * DistToReticleY)
    'get cosine
    DX = DistToReticleX/hypot
    DY = DistToReticleY/hypot
 End Function

This code makes the mouse button shoot:
Code: [Select]
Sub Display_MouseDown(Button, Shift, X, Y)
   Dim NewSpr, DX, DY
   If nShot1Count >= 3 Then Exit Sub
   Set NewSpr = ProjectObj.GamePlayer.rMap.SpriteDefs("bullet").MakeInstance
   Set arBtn1Shots(nShot1Count) = NewSpr
   nShot1Count = nShot1Count + 1
   With ProjectObj.GamePlayer.PlayerSprite
      .rDef.rLayer.AddSprite HostObj.AsObject(NewSpr)
      nExpectCount = nExpectCount + 1
      NewSpr.X = .X + (.Width - NewSpr.Width) / 2
      NewSpr.Y = .Y + (.Height - NewSpr.Height) / 2
      GetStateDeltas DX, DY
      NewSpr.DX = DX * NewSpr.rDef.Template.MoveSpeed
      NewSpr.DY = DY * NewSpr.rDef.Template.MoveSpeed
      If NewSpr.rDef.Template.StateCount = 36 Then NewSpr.CurState = RectToPolarState(DX, DY)
   End With
End Sub

Thanks again for all your help! In case you're curious, this is what I'm working on. You can see a screenshot here.