Delta67 发表于 2015-6-8 15:29:47

有自己做stg的前辈吗 想请教下弹幕的算法

用的是C++和DX9 (因为还是xp的系统 最高只能dx9了 然而大约不久后会换机子吧)
关于弹幕的移动 主要是考虑到弹幕并不一定是直线移动的(可能涉及奇怪的弧线或者中途变成狙之类的) 所以大概不大好用csv之类的记录一串数据直线移动就做出来
当前的做法是 弹幕的class里面有个函数指针成员pFunc 然后每次移动的时候如果pFunc==NULL 则当前的x和y坐标分别加上vx和vy 如果pFunc不是NULL则跑这个函数来改变弹幕的相应参数 这样就可以写各种不同的弹幕移动函数了

但是昨天在测试的时候试着写了个恋恋的本我(原作心弹素材 显示方面用的是sprite) 在全屏才100弹幕左右的时候就已经开始频繁的掉帧 而且我现在自机都没做 都是无判定弹幕 再加上弹幕判定可能会更卡
想请教下前辈们是怎么处理弹幕的算法的 谢谢大家
因为C++和DX9都是自学的 所以很多地方可能知识点有疏漏可能会有追问 或是问题表述不清楚还请见谅

song_5007 发表于 2015-6-8 17:37:26

_(:з」∠)_真是厉害啊,【关注此问题←我也想知道(虽然我能撑几千弹幕才掉帧,,不过大概是电脑比较好的原因)

fancydz 发表于 2015-6-8 17:49:22

Delta67 发表于 2015-6-8 18:01:59

song_5007 发表于 2015-6-8 17:37 static/image/common/back.gif
_(:з」∠)_真是厉害啊,【关注此问题←我也想知道(虽然我能撑几千弹幕才掉帧,,不过大概是电脑比较好的原 ...

哇 几千弹幕很酷炫诶 请问前辈是什么做法

Delta67 发表于 2015-6-8 18:02:35

fancydz 发表于 2015-6-8 17:49 static/image/common/back.gif
同关注此问题
因为找不到顺手的弹幕编写方式
所以一直处于半弃坑状态,一直在打别人家的飞机

我也在打别人的飞机(怎么听起来那么少儿不宜

漆黑之翼 发表于 2015-6-8 21:29:12

你掉帧是用debug测的吗……
不论怎样,100弹就掉帧也太……

drzzm32 发表于 2015-6-8 21:45:53

额这个。。。。我是用vb.net,大概2W之后才有比较明显掉帧。。。

Sonicthedgehog 发表于 2015-6-9 00:55:19

刚刚看了一下,感觉本我[本能的释放]这张应该不难写,弹幕class里边存储几个简单数据即可:坐标,速度,角度,速度增量,角度增量。
放弹时以BOSS为坐标,有一定初速度,方向是圆形四周各个方向,速度增量设成负的,每次同方向发弹发两弹,然后把方向增量设成一正一副两个绝对值相等的数。最后在每帧处理的时候限定一下弹幕的最低速度就可以了。

这样就不用每个弹幕单跑一次函数了,只用作简单的加减法和三角函数计算就可以了。

http://img4q.duitang.com/uploads/item/201506/09/20150609004810_K8mcA.gif

这个效果其实不够好。

更可行的方法是弄个叫Anim的类,里边存储弹幕在不同时刻的数据。
在弹幕类里边声明anim为他的属性之一,平时可以空着,像这张卡的时候可以可以填上3个anim,
分别对应
1 弹幕开始发出时速度正常,只有一定角加速度的状态
2 弹幕转弯一段时间后减速,速度增量为负,角加速度随着减小的状态
3 弹幕不再减速后,只有速度和角度的状态

根据弹幕发出后的时间决定套用哪个anim的计算方式。
弹幕时间可以在每次帧处理时+1。


(以上均为口胡。)

krh 发表于 2015-6-9 03:08:07

本帖最后由 krh 于 2015-6-8 14:11 编辑

100 确实太少了

是哪里搜索了 或者大量循环才会这样吧(看起来100*100 次计算距离比较符合计算机的速度

drzzm32 发表于 2015-6-9 09:29:48

Public Class STG3D
      ' STG相关的数据结构和函数
      ' 此类不可实例化

      Public Const DivideNum As Integer = 12

      Public Const JUDGE_GRAZE As Integer = 1
      Public Const JUDGE_MISS As Integer = 2
      Public Const JUDGE_AWAY As Integer = 3

      Public Const TEX_SPHERE As Integer = -2
      Public Const TEX_CIRCLE As Integer = -1

      Public Class Bullet
            ' 抽象的弹幕类
            ' 也可作为物体的基类

            Private Position As Base.Point3D
            Private Speed As Base.Point3D
            Private Rotate As Base.Point3D
            Private Scale As Base.Point3D
            Private TexPtr As Integer
            Private Texture As DxVB.DxImage
            Public IsEnabled As Boolean
            Public IsGrazed As Boolean

            Public Sub New()
                Position.x = 0 : Position.y = 0 : Position.z = 0
                Speed.x = 0 : Speed.y = 0 : Speed.z = 0
                Rotate.x = 0 : Rotate.y = 0 : Rotate.z = 0
                Scale.x = 0 : Scale.y = 0 : Scale.z = 0
                TexPtr = 0 : IsEnabled = False : IsGrazed = True
                Texture = New DxVB.DxImage
            End Sub

            Public Sub New(ByVal Texture As DxVB.DxImage)
                Position.x = 0 : Position.y = 0 : Position.z = 0
                Speed.x = 0 : Speed.y = 0 : Speed.z = 0
                Rotate.x = 0 : Rotate.y = 0 : Rotate.z = 0
                Scale.x = 0 : Scale.y = 0 : Scale.z = 0
                TexPtr = Texture.Handle : IsEnabled = False : IsGrazed = True
                Me.Texture = Texture
            End Sub

            Public Sub SetTexture(ByVal Texture As DxVB.DxImage)
                TexPtr = Texture.Handle
                Me.Texture = Texture
            End Sub

            Public Function GetPosition() As Base.Point3D
                Return Position
            End Function

            Public Sub SetPosition(ByVal x As Double, ByVal y As Double, ByVal z As Double)
                Position.x = x : Position.y = y : Position.z = z
            End Sub

            Public Sub SetPosition(ByRef Point As Base.Point3D)
                Position = Point
            End Sub

            Public Function GetSpeed() As Base.Point3D
                Return Speed
            End Function

            Public Sub SetSpeed(ByVal x As Double, ByVal y As Double, ByVal z As Double)
                Speed.x = x : Speed.y = y : Speed.z = z
            End Sub

            Public Sub SetSpeed(ByRef Point As Base.Point3D)
                Speed = Point
            End Sub

            Public Sub SetRotate(ByVal x As Double, ByVal y As Double, ByVal z As Double)
                Rotate.x = x : Rotate.y = y : Rotate.z = z
            End Sub

            Public Sub SetScale(ByVal x As Double, ByVal y As Double, ByVal z As Double)
                Scale.x = x : Scale.y = y : Scale.z = z
            End Sub

            Public Function PreJudge(ByRef Point As Base.Point3D, ByVal Range As Double) As Boolean
                Return Math.Abs(Point.x - Position.x) < Range And Math.Abs(Point.y - Position.y) < Range And Math.Abs(Point.z - Position.z) < Range
            End Function

            Public Function PreJudge(ByRef Point As Base.Point3D, ByVal RangeX As Double, ByVal RangeY As Double, ByVal RangeZ As Double) As Boolean
                Return Math.Abs(Point.x - Position.x) < RangeX And Math.Abs(Point.y - Position.y) < RangeY And Math.Abs(Point.z - Position.z) < RangeZ
            End Function

            Public Function Judge(ByRef Point As Base.Point3D) As Integer
                If (Base.Distance3D(Point, Position) > Base.Average3D(Scale) * 1.5D) Then
                  Return JUDGE_AWAY
                ElseIf (Base.Distance3D(Point, Position) > Base.Average3D(Scale)) Then
                  Return JUDGE_GRAZE
                Else
                  Return JUDGE_MISS
                End If
            End Function

            Public Function Distance(ByRef Bullet As Bullet) As Single
                Return Base.Distance3D(Position, Bullet.GetPosition())
            End Function

            Public Sub Draw()
                'If TexPtr = -2 Then DxVB.DrawSphere(Position.x, Position.y, Position.z, Base.Average3D(Scale), DivideNum, 255, 255, 255, 0, 0, 0, True)
                'If TexPtr = -1 Then DxVBDLL.DX.DrawCircle(Position.x, Position.z, Base.Average3D(Scale), DX.GetColor(255, 255, 255))
                'If TexPtr > 0 Then DxVB.DrawPic(Texture, Position.x, Position.z)
                If TexPtr = 0 Then DX.DrawPixel(Position.x, Position.z, &HFFFFFF)
                DxVB.DrawPic(Texture, Position.x, Position.z, Base.Average3D(Rotate))
            End Sub
      End Class

      Public Class STGCore
            ' STG的核心函数在这里
            ' 包括绘制,判定和控制
            ' 弹幕生成需要继承这个类
            ' 此类需要实例化

            Protected ArrayNumA As Integer
            Protected ArrayNumB As Integer
            Protected Bullets As Bullet(,)
            Public Shared Player As Bullet
            Protected Shared OriPlayer As Base.Point3D
            Protected Shared GameCenter As Bullet
            Protected CorePosition As Bullet
            Protected Shared GameRange As Double
            Protected Shared DefaultTex As Integer
            Protected Shared Graze, Miss, Num As Integer
            'Protected STGThread As Thread

            Public Shared Sub InitShared(ByVal CenterX As Double, ByVal CenterY As Double, ByVal CenterZ As Double, ByVal Range As Double, _
                            ByVal PlayerX As Double, ByVal PlayerY As Double, ByVal PlayerZ As Double, ByVal PlayerSize As Double, ByVal DefaultTexture As Integer)
                Player = New Bullet(New DxVB.DxImage)
                Player.SetPosition(PlayerX, PlayerY, PlayerZ)
                Player.SetScale(PlayerSize, PlayerSize, PlayerSize)
                Player.IsEnabled = True
                OriPlayer = Player.GetPosition()
                GameCenter = New Bullet()
                GameCenter.SetPosition(CenterX, CenterY, CenterZ)
                GameRange = Range : DefaultTex = DefaultTexture
                Graze = 0 : Miss = 0 : Num = 0
            End Sub

            Public Sub New(ByVal ArrayNum1 As Integer, ByVal ArrayNum2 As Integer, ByVal CenterX As Double, ByVal CenterY As Double, ByVal CenterZ As Double, ByVal Range As Double, _
                            ByVal PlayerX As Double, ByVal PlayerY As Double, ByVal PlayerZ As Double, ByVal PlayerSize As Double, ByVal DefaultTexture As Integer)
                ArrayNumA = ArrayNum1
                ArrayNumB = ArrayNum2
                ReDim Bullets(ArrayNumA, ArrayNumB)
                InitBullet()
                Player = New Bullet(New DxVB.DxImage)
                Player.SetPosition(PlayerX, PlayerY, PlayerZ)
                Player.SetScale(PlayerSize, PlayerSize, PlayerSize)
                Player.IsEnabled = True
                OriPlayer = Player.GetPosition()
                GameCenter = New Bullet()
                GameCenter.SetPosition(CenterX, CenterY, CenterZ)
                CorePosition = New Bullet()
                CorePosition.SetPosition(CenterX, CenterY, CenterZ)
                GameRange = Range : DefaultTex = DefaultTexture
                'STGThread = New Thread(JudgeACtrl)
            End Sub

            Public Sub New(ByVal ArrayNum1 As Integer, ByVal ArrayNum2 As Integer, ByVal CenterX As Double, ByVal CenterY As Double, ByVal CenterZ As Double)
                ArrayNumA = ArrayNum1
                ArrayNumB = ArrayNum2
                ReDim Bullets(ArrayNumA, ArrayNumB)
                InitBullet()
                CorePosition = New Bullet()
                CorePosition.SetPosition(CenterX, CenterY, CenterZ)
                'STGThread = New Thread(JudgeACtrl)
            End Sub

            Public Sub Run()
                'STGThread.Start();
            End Sub

            Public Sub Close()
                'STGThread.Abort();
            End Sub

            Public Sub GetInfo(ByVal x As Single, ByVal y As Single)
                DxVB.DrawString("Graze: " + Graze.ToString(), x, y, 20)
                DxVB.DrawString("Miss:" + Miss.ToString(), x, y + 25, 20)
                DxVB.DrawString("Num: " + Num.ToString(), x, y + 50, 20)
            End Sub

            Public Shared Sub GetInfo(ByRef Miss As Integer, ByRef Graze As Integer, ByRef Num As Integer)
                Miss = STGCore.Miss : Graze = STGCore.Graze : Num = STGCore.Num
            End Sub

            Public Function GetCenter() As Base.Point3D
                Return CorePosition.GetPosition()
            End Function

            Public Sub SetCenter(ByVal Point As Base.Point3D)
                CorePosition.SetPosition(Point)
            End Sub

            Private Sub InitBullet()
                For i = 0 To Bullets.GetUpperBound(0) Step 1
                  For j = 0 To Bullets.GetUpperBound(1) Step 1
                        Bullets(i, j) = New Bullet()
                  Next j
                Next i
            End Sub

            Public Sub MainCircle()
                GenBullet()
                JudgeBullet()
                DrawBullet()
            End Sub

            Public Sub MainCircle(ByVal Time As Long, ByVal JmpRate As Integer)
                GenBullet()
                JudgeBullet()
                If Time Mod JmpRate = 0 Then DrawBullet()
            End Sub

            Protected Overridable Sub GenBullet()
                Dim TmpPoint As Base.Point3D
                For i = 0 To ArrayNumA - 1
                  For j = 0 To ArrayNumB - 1
                        If Not Bullets(i, j).IsEnabled Then
                            TmpPoint.x = CorePosition.GetPosition().x
                            TmpPoint.y = CorePosition.GetPosition().y
                            TmpPoint.z = CorePosition.GetPosition().z
                            Bullets(i, j).SetPosition(TmpPoint)
                            Bullets(i, j).SetScale(20, 20, 20)
                            Bullets(i, j).IsEnabled = True
                        End If
                        TmpPoint.x = 0
                        TmpPoint.y = 0
                        TmpPoint.z = 0
                        TmpPoint.x = Bullets(i, j).GetPosition().x + TmpPoint.x
                        TmpPoint.y = Bullets(i, j).GetPosition().y + TmpPoint.y
                        TmpPoint.z = Bullets(i, j).GetPosition().z + TmpPoint.z
                        If Base.Distance3D(Bullets(i, j).GetPosition(), GameCenter.GetPosition()) > GameRange Then
                            Bullets(i, j) = New EngineCore.STG3D.Bullet()
                        End If
                  Next j
                Next i
            End Sub

            Protected Overridable Sub DrawBullet()
                For i = 0 To Bullets.GetUpperBound(0) Step 1
                  For j = 0 To Bullets.GetUpperBound(1) Step 1
                        If Bullets(i, j).IsEnabled Then Bullets(i, j).Draw()
                  Next j
                Next i
                DrawPlayer()
            End Sub

            Protected Shared Sub DrawPlayer()
                Player.Draw()
            End Sub

            Protected Overridable Sub JudgeBullet()
                Num = 0
                For i = 0 To Bullets.GetUpperBound(0) Step 1
                  For j = 0 To Bullets.GetUpperBound(1) Step 1
                        If Bullets(i, j).IsEnabled Then
                            If GameCenter.PreJudge(Bullets(i, j).GetPosition(), GameRange) Then
                              Num = Num + 1
                            Else
                              Bullets(i, j) = New Bullet()
                            End If
                        End If
                  Next j
                Next i

                For i = 0 To Bullets.GetUpperBound(0) Step 1
                  For j = 0 To Bullets.GetUpperBound(1) Step 1
                        If Bullets(i, j).IsEnabled Then
                            If Bullets(i, j).IsEnabled And Player.PreJudge(Bullets(i, j).GetPosition(), GameRange) Then
                              If Player.Judge(Bullets(i, j).GetPosition()) = JUDGE_AWAY And Not Bullets(i, j).IsGrazed Then
                                    Bullets(i, j).IsGrazed = True
                              End If
                              If Player.Judge(Bullets(i, j).GetPosition()) = JUDGE_GRAZE And Bullets(i, j).IsGrazed Then
                                    Bullets(i, j).IsGrazed = False
                                    Graze = Graze + 1
                              End If
                              If Player.Judge(Bullets(i, j).GetPosition()) = JUDGE_MISS Then
                                    Bullets(i, j) = New Bullet()
                                    Miss = Miss + 1
                                    Player.SetPosition(OriPlayer)
                              End If
                            End If
                        End If
                  Next j
                Next i
            End Sub

            Public Shared Sub Control()
                Dim TmpPos As Base.Point3D
                TmpPos = Player.GetPosition()
                If DefaultTex = TEX_SPHERE Then
                  If Base.GetKey(Base.Keys.KeyLSHIFT) Or Base.GetKey(Base.Keys.KeyRSHIFT) Then
                        If Base.GetKey(Base.Keys.KeyUP) Then
                            TmpPos.z = TmpPos.z + 3
                        End If
                        If Base.GetKey(Base.Keys.KeyDOWN) Then
                            TmpPos.z = TmpPos.z - 3
                        End If
                        If Base.GetKey(Base.Keys.KeyLEFT) Then
                            TmpPos.x = TmpPos.x - 3
                        End If
                        If Base.GetKey(Base.Keys.KeyRIGHT) Then
                            TmpPos.x = TmpPos.x + 3
                        End If
                  Else
                        If Base.GetKey(Base.Keys.KeyUP) Then
                            TmpPos.z = TmpPos.z + 5
                        End If
                        If Base.GetKey(Base.Keys.KeyDOWN) Then
                            TmpPos.z = TmpPos.z - 5
                        End If
                        If Base.GetKey(Base.Keys.KeyLEFT) Then
                            TmpPos.x = TmpPos.x - 5
                        End If
                        If Base.GetKey(Base.Keys.KeyRIGHT) Then
                            TmpPos.x = TmpPos.x + 5
                        End If
                  End If
                Else
                  If Base.GetKey(Base.Keys.KeyLSHIFT) Or Base.GetKey(Base.Keys.KeyRSHIFT) Then
                        If Base.GetKey(Base.Keys.KeyUP) Then
                            TmpPos.z = TmpPos.z - 3
                        End If
                        If Base.GetKey(Base.Keys.KeyDOWN) Then
                            TmpPos.z = TmpPos.z + 3
                        End If
                        If Base.GetKey(Base.Keys.KeyLEFT) Then
                            TmpPos.x = TmpPos.x - 3
                        End If
                        If Base.GetKey(Base.Keys.KeyRIGHT) Then
                            TmpPos.x = TmpPos.x + 3
                        End If
                  Else
                        If Base.GetKey(Base.Keys.KeyUP) Then
                            TmpPos.z = TmpPos.z - 6
                        End If
                        If Base.GetKey(Base.Keys.KeyDOWN) Then
                            TmpPos.z = TmpPos.z + 6
                        End If
                        If Base.GetKey(Base.Keys.KeyLEFT) Then
                            TmpPos.x = TmpPos.x - 6
                        End If
                        If Base.GetKey(Base.Keys.KeyRIGHT) Then
                            TmpPos.x = TmpPos.x + 6
                        End If
                  End If
                End If
                If GameCenter.PreJudge(TmpPos, 432, 1, 504) Then Player.SetPosition(TmpPos)
            End Sub
      End Class这是我用的STG类,应该能做下参考。
继承STGCore类,重写GenBullet,再创建对象,执行MainCircle。

对于帧率控制
Public Class FPSCounter
            ' 进行帧率计算和控制的类
            ' 此类需要实例化
            ' 精度为小数点后一位
            ' 其中的Update要加入主游戏循环

            Private StartTime As Integer
            Private Count As Integer
            Private FPSNum As Single
            Private Const N As Integer = 60
            Private Const FPS As Integer = 60

            Public Sub New()
                StartTime = 0
                Count = 0
                FPSNum = 0
            End Sub

            Public Sub Update()
                If Count = 0 Then
                  StartTime = System.Environment.TickCount
                End If
                If Count = N Then
                  Dim TmpTime As Integer = System.Environment.TickCount
                  FPSNum = 1000.0F / ((CType(TmpTime, Single) - CType(StartTime, Single)) / CType(N, Single))
                  Count = 0
                  StartTime = TmpTime
                End If
                Count = Count + 1
            End Sub

            Public Sub WaitTime()
                Dim TookTime As Integer = System.Environment.TickCount - StartTime
                Dim WaitTime As Integer = Count * 1000 / FPS - TookTime

                If WaitTime > 0 Then
                  DX.WaitTimer(WaitTime)
                End If
            End Sub

            Public Function GetFPS(ByVal Digits As Integer) As Single
                Return Math.Round(FPSNum, Digits)
            End Function

            Public Function GetFPS() As Single
                Return FPSNum
            End Function

      End Class感觉还是垂直同步方便(((
页: [1] 2
查看完整版本: 有自己做stg的前辈吗 想请教下弹幕的算法