none
Sprite Attacks Sprite but doesn't determine that it is destroyed instead it is still standing

    Question

  • An unhandled exception of type 'System.InvalidCastException' occurred in mscorlib.dll

    Additional information: Unable to cast object of type 'Sprite' to type 'System.IConvertible'.

    these are the following errors which appear on my screen. 

    Dim hp As Integer = Convert.ToInt32(Sprites(1)) = 10
            Dim cp As Integer = Convert.ToInt32(Sprites(2)) = 10
    
            If hp <= 0 Then
                hp = hp - cp
                MsgBox("Tank Destroyed")
            End If


    This is my version of the code which shows the error. The sprites is a new list of sprites which is what it is declared as.

        Private Sprites As New List(Of Sprite)

    In a nutshell what I want to do is where one of the tanks have 10 health points and another tank has 10 attack points and when I select the tank I assigned with the attack points to attack the tank with healthpoints, then a msgbox will determine if the tank has been sucessfully destroyed or not. 

    Please feel free to post any questions for further detail. Let me know if I should be doing something particularly. 



    Thursday, March 16, 2017 8:32 PM

Answers

  •  Private Class Sprite
            Public Pic As PictureBox
            Public ColRow As Point
            Public Steps As Integer = -1    '-1 = unlimited move
            Public Visible As Integer = 2   '0 = not visible  1= Frozen  2=Active   
            Public HP As Integer
            Public AP As Integer
        End Class

    I have assigned the sprites with an integer as so.

            Sprites(1).HP = 10
            Sprites(2).HP = 10
    
    
            Sprites(1).AP = 10
            Sprites(2).AP = 10

    These have been put in the form1_load area 

    Then here is the button to determine whether sprite 1 will stay standing or not. 

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            If Sprites(1).HP = 0 Then
                Sprites(1).HP = Sprites(1).HP - Sprites(2).AP
                MsgBox("Murked")
            Else
                MsgBox("Still standing")
            End If
    
        End Sub
    Have I done something wrong here such as put the sprites set HP in the wrong form load and rather it should be in the class sprite


    WRA

    These are both wrong:

            If Sprites(1).HP <= 0 Then
                Sprites(1).HP = Sprites(1).HP - Sprites(2).AP - 10
                Sprites(1).HP = Label1.Text
                MsgBox("Murked")
            Else
                MsgBox("Still standing")
            End If
            If Sprites(1).HP = 0 Then
                Sprites(1).HP = Sprites(1).HP - Sprites(2).AP
                MsgBox("Murked")
            Else
                MsgBox("Still standing")
            End If

    In both cases, you are only going to execute the code to reduce Sprite(1).HP if it is already at zero!  That doesn't make sense.  You want to reduce the HP if the HP is NOT zero - if the HP is zero, the object should already be destroyed and should no longer be a viable target for another attack.

            Sprites(1).HP = Sprites(1).HP - Sprites(2).AP       
            If Sprites(1).HP <= 0 Then
                MsgBox("Murked")
                'remove sprite from list
            Else
                MsgBox("Still standing")
            End If


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"


    Friday, March 17, 2017 11:17 PM
    Moderator
  • I couldn't help myself...

    Here's an example of a 2 player tank game.  It's not precisely the same kind of game you are making so it shouldn't be useful from the perspective of handing it in for an assignment.  However, it does demonstrate all of the key components you would need for your game engine and gives you an example of what all of the necessary objects should look like and how they should work together.

    In this game, two players drive tanks around an open map and try to shoot each other.  Player 1 uses WASD to move and E to shoot while Player 2 uses IJKL to move and U to shoot.  Each tank can take 10 shots before being destroyed.

    The map is drawn with a tiled image, but does not enforce any grid-based movement.  In your own version of the game engine, your game map would define the map cell size and dimensions and your game object would move according to cell positions instead of raw pixel locations.  These are simply adjustments to the behavior logic used in the following example game engine.

    To use the following example, create a new Windows Forms project.  In the solution explorer, right click the project and select Add Folder.  Add a folder named Assets to the project.  Download the following two images and add them to the Assets folder by right clicking the folder and selecting Add Existing Item.

    Tank Game Sprite SheetExplosion Animation Strip

    To ensure compatibility with the code, make sure the file names you save are TankGameSpriteSheet.png and explosion.png.

    After adding the files to the Asset folder, select the first and then go to the properties window and set the Copy to Output Directory property to Copy Always.  Repeat this process for the other file.

    Tank Game Assest Properties

    With the assets in place you can paste the following code over top of the default Form1 code.  I know it looks like a lot of code, but as you read through it you will find that it is really a just a number of relatively small objects.  I've tried to separate the code into regions and add some comments to help explain what things are and what they do.  I hope you'll be able to read over it a couple of times, follow through the logic, and gain an understanding of how a game loop should execute.

    Option Strict On
    
    'example form
    Public Class Form1
        'declare a game engine variable
        Private engine As GameEngine
    
        'execute the Load event handler asynchronously
        Private Async Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            'set the form size and border style
            ClientSize = New Size(800, 600)
            FormBorderStyle = FormBorderStyle.FixedSingle
    
            'create the new game engine instance and load the image assets
            engine = New GameEngine(Me)
            engine.LoadAssets()
    
            'create, configure, and assign the background map
            Dim mapSprite As New Sprite
            mapSprite.SpriteSheet = engine.SpriteSheets("TankGameSpriteSheet")
            mapSprite.Bounds = New RectangleF(192, 0, 96, 96)
            engine.GameMap = New GameMap With {.TileSprite = mapSprite}
    
            'create the two player tanks and add them to the game
            engine.AddObject(New Player1Tank With {.Position = New PointF(50, 100)})
            engine.AddObject(New Player2Tank With {.Position = New PointF(750, 100)})
    
            Try
                'run the game
                Await engine.Run
            Catch ex As Exception
                Stop 'stop here during debugging to examine the error which occured
            End Try
        End Sub
    
        'end the game when the form closes
        Private Sub Form1_Closing(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles Me.Closing
            engine.Stop()
        End Sub
    
        Private Sub Form1_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
            'notify the engine when a key is pressed
            engine.Input.SetKeyState(e.KeyCode, True)
        End Sub
    
        Private Sub Form1_KeyUp(sender As Object, e As KeyEventArgs) Handles Me.KeyUp
            'notify the engine when a key is released
            engine.Input.SetKeyState(e.KeyCode, False)
        End Sub
    
    End Class
    
    #Region " Game Actors (GameObject Instances) "
    
    'Define a base Tank class which each Player Tank can inherit
    Public MustInherit Class Tank
        Inherits GameObject
        'Add hit points and attack points to the game object
        Public Property HP As Integer
        Public Property AP As Integer
        'Set the reload time (or cooldown) for each shot and the range a fired shot can travel
        Public Property ReloadTime As Single = 2.0!
        Public Property Range As Single = 280.0!
        'Specify the tank's turning rate in degrees-per-second
        Public Property TurnRate As Single = 7.5!
        'Holds the input key map for the player
        Public Property ForwardKey As Keys
        Public Property BackKey As Keys
        Public Property TurnLeftKey As Keys
        Public Property TurnRightKey As Keys
        Public Property FireKey As Keys
    
        'private variable for current cool down value
        Private coolDown As Single
    
        'gets the location of the end of the tank barrel 
        Public Function GetBarrelPosition() As PointF
            Return MathF.GetPositionToward(Position, FacingAngle, 48)
        End Function
    
        'sets common tank properties
        Public Overrides Sub OnInitialize(e As GameEngine)
            MyBase.OnInitialize(e)
            Sprite = New Sprite
            Sprite.SpriteSheet = e.SpriteSheets("TankGameSpriteSheet")
            Collider = New CircleCollider(Me)
            Collider.Origin = New PointF(-24, 0)
            Collider.Radius = 20.0!
            Speed = 24
            HP = 100
            AP = 10
        End Sub
    
        'process behaviors for a tank
        Public Overrides Sub OnUpdate(e As GameEngine)
            MyBase.OnUpdate(e)
            'if the HP is zero or less, destroy the tank
            If HP <= 0 Then
                e.RemoveObject(Me)
                Dim explosion As New Explosion
                explosion.Position = Position
                e.AddObject(explosion)
                Exit Sub
            End If
            'if there is a cool down running, reduce it
            If coolDown > 0 Then coolDown -= e.Time.LastFrame
            'process left/right input to adjust the facing angle
            If e.Input.IsDown(TurnLeftKey) Then
                FacingAngle = MathF.WrapDegrees(FacingAngle - TurnRate * e.Time.LastFrame)
            End If
            If e.Input.IsDown(TurnRightKey) Then
                FacingAngle = MathF.WrapDegrees(FacingAngle + TurnRate * e.Time.LastFrame)
            End If
            'process forward/back movement to update the position
            If e.Input.IsDown(ForwardKey) Then
                Position = MathF.GetPositionToward(Position, FacingAngle, Speed * e.Time.LastFrame)
            End If
            If e.Input.IsDown(BackKey) Then
                Position = MathF.GetPositionToward(Position, MathF.WrapDegrees(FacingAngle + MathF.HALF_CIRCLE), Speed * e.Time.LastFrame)
            End If
            'process the fire key by creating a new bullet
            If e.Input.WasPressed(FireKey) AndAlso coolDown <= 0 Then
                Dim bullet As New Bullet
                bullet.Position = GetBarrelPosition()
                bullet.FacingAngle = FacingAngle
                bullet.MaxDistance = Range
                bullet.AttackPower = AP
                e.AddObject(bullet)
                coolDown = ReloadTime
            End If
        End Sub
    End Class
    
    'configure a tank with player 1 image and keymap
    Public Class Player1Tank
        Inherits Tank
        Public Overrides Sub OnInitialize(e As GameEngine)
            MyBase.OnInitialize(e)
            Sprite.Bounds = New RectangleF(0, 0, 44, 96)
            ForwardKey = Keys.W
            BackKey = Keys.S
            TurnLeftKey = Keys.A
            TurnRightKey = Keys.D
            FireKey = Keys.E
        End Sub
    End Class
    
    'configure a tank with player 2 image and keymap
    Public Class Player2Tank
        Inherits Tank
        Public Overrides Sub OnInitialize(e As GameEngine)
            MyBase.OnInitialize(e)
            Sprite.Bounds = New RectangleF(52, 0, 43, 96)
            ForwardKey = Keys.I
            BackKey = Keys.K
            TurnLeftKey = Keys.J
            TurnRightKey = Keys.L
            FireKey = Keys.U
        End Sub
    End Class
    
    'create a bullet which moves along a given trajectory for a given distance
    Public Class Bullet
        Inherits GameObject
    
        'hold the attack power of the tank which created the bullet
        Public AttackPower As Integer
        'hold the range that the tank can fire
        Public MaxDistance As Single
        'private variable to track distance traveled
        Private remainingDistance As Single
    
        Public Overrides Sub OnInitialize(e As GameEngine)
            MyBase.OnInitialize(e)
            Sprite = New Sprite
            Sprite.SpriteSheet = e.SpriteSheets("TankGameSpriteSheet")
            Sprite.Bounds = New RectangleF(288, 0, 8, 16)
            Collider = New CircleCollider(Me)
            Collider.Origin = New PointF(-4, 0)
            Collider.Radius = 4.0!
            Speed = 96
            ZOrder = 2
            remainingDistance = MaxDistance
        End Sub
    
        'handle collision with a tank
        Public Overrides Function OnCollision(e As GameEngine, other As GameObject) As Boolean
            'when a tank is hit
            If TypeOf other Is Tank Then
                'reduce the tank HP
                CType(other, Tank).HP -= AttackPower
                'remove the bullet from the game 
                e.RemoveObject(Me)
                'create a small explosion at the collision point
                Dim hit As New Explosion
                hit.Position = Position
                hit.Scale = 0.1
                e.AddObject(hit)
                'return true because this object was destroyed by the collision
                Return True
            End If
            Return MyBase.OnCollision(e, other)
        End Function
    
        'move the bullet along its trajectory until the max distance has expired
        Public Overrides Sub OnUpdate(e As GameEngine)
            MyBase.OnUpdate(e)
            Dim newPosition = MathF.GetPositionToward(Position, FacingAngle, Speed * e.Time.LastFrame)
            remainingDistance -= MathF.Distance(Position, newPosition)
            If remainingDistance > 0 Then
                Position = newPosition
            Else
                e.RemoveObject(Me)
            End If
        End Sub
    End Class
    
    'create an animated explosion effect
    Public Class Explosion
        Inherits GameObject
    
        'provide a scale factor for the animation image (its easy to scale an object with no collider)
        Public Property Scale As Single = 1.0!
    
        'keep track of the frames of animation and playback rate
        Private frameTime As Single = 1.0! / 33.0!
        Private frameCount As Integer = 14
    
        'initialize the explosion to the first frame
        Public Overrides Sub OnInitialize(e As GameEngine)
            MyBase.OnInitialize(e)
            Sprite = New Sprite
            Sprite.SpriteSheet = e.SpriteSheets("explosion")
            Sprite.Bounds = New RectangleF(0, 0, 110, 110)
            ZOrder = 3
        End Sub
    
        'perform a custom render so that the image can be scaled
        Public Overrides Sub OnRender(e As GameEngine, gfx As Graphics)
            gfx.TranslateTransform(Position.X, Position.Y)
            gfx.ScaleTransform(Scale, Scale) 'add a scale operation to normal drawing
            gfx.RotateTransform(MathF.WrapDegrees(FacingAngle + MathF.RIGHT_ANGLE))
            gfx.TranslateTransform(-Position.X, -Position.Y)
            Dim dstBounds = New RectangleF(Position.X - Sprite.Bounds.Width / 2.0!, Position.Y - Sprite.Bounds.Height / 2.0!, Sprite.Bounds.Width, Sprite.Bounds.Height)
            gfx.DrawImage(Sprite.SpriteSheet, dstBounds, Sprite.Bounds, GraphicsUnit.Pixel)
            gfx.ResetTransform()
        End Sub
    
        'update the frames of the animation until it finishes, then destroy the object
        Public Overrides Sub OnUpdate(e As GameEngine)
            MyBase.OnUpdate(e)
            frameTime -= e.Time.LastFrame
            If frameTime <= 0 Then
                frameCount -= 1
                If frameCount = 0 Then
                    e.RemoveObject(Me)
                Else
                    Sprite.Bounds = New RectangleF(Sprite.Bounds.X + Sprite.Bounds.Width, Sprite.Bounds.Y, Sprite.Bounds.Width, Sprite.Bounds.Height)
                End If
            End If
        End Sub
    End Class
    #End Region
    
    #Region " Game Engine Objects "
    'define the main game engine
    Public Class GameEngine
        'track the keyboard input
        Public ReadOnly Property Input As New GameInput
        'track the game execution time
        Public ReadOnly Property Time As New GameClock
        'hold an instance of the current game map
        Public Property GameMap As GameMap
        'hold a dictionary of spritsheets keyed by file name
        Public ReadOnly Property SpriteSheets As New Dictionary(Of String, Image)
        'indicate if the engine is running
        Public ReadOnly Property IsRunning As Boolean
        'hold the client size of the render window
        Public ReadOnly Property WindowSize As SizeF
    
        'create a private graphics buffer for rendering
        Private graphicsBuffer As BufferedGraphics
        'create a private list of active game object instances
        Private gameObjects As New List(Of GameObject)
        'create a queue to hold new game objects which need to be initialized and added to the game
        Private newObjectQueue As New Queue(Of GameObject)
    
        'create the game engine instance with a reference to the control where the game will be rendered
        Public Sub New(canvasControl As Control)
            graphicsBuffer = BufferedGraphicsManager.Current.Allocate(canvasControl.CreateGraphics, canvasControl.ClientRectangle)
            WindowSize = canvasControl.ClientSize
        End Sub
    
        'provide a method for adding new game objects to the engine
        Public Sub AddObject(obj As GameObject)
            newObjectQueue.Enqueue(obj)
        End Sub
    
        'load all sprite sheets from the .png files in the local Assets folder
        Public Sub LoadAssets()
            For Each imageFile In IO.Directory.GetFiles(IO.Path.Combine(My.Application.Info.DirectoryPath, "Assets"), "*.png")
                SpriteSheets(IO.Path.GetFileNameWithoutExtension(imageFile)) = Bitmap.FromFile(imageFile)
            Next
        End Sub
    
        'provide a method for removing a game object from the engine
        Public Sub RemoveObject(obj As GameObject)
            gameObjects.Remove(obj)
        End Sub
    
        'execute the main game loop to run the game
        Public Async Function Run() As Task
            If Not _IsRunning Then
                _IsRunning = True
                'enter the main game loop
                Do While _IsRunning
                    'update the game execution time
                    Time.Update()
                    'initialize new game objects and add them to the game
                    While newObjectQueue.Count > 0
                        Dim obj = newObjectQueue.Dequeue
                        If Not obj.IsInitialized Then obj.OnInitialize(Me)
                        gameObjects.Add(obj)
                    End While
                    'check collision of game objects
                    For i = gameObjects.Count - 1 To 1 Step -1
                        Dim obj1 = gameObjects(i)
                        If obj1.Collider IsNot Nothing Then
                            For j = i - 1 To 0 Step -1
                                Dim obj2 = gameObjects(j)
                                If obj2.Collider IsNot Nothing Then
                                    If obj1.Collider.CollidesWith(obj2.Collider) Then
                                        obj2.OnCollision(Me, obj1)
                                        If obj1.OnCollision(Me, obj2) Then Exit For
                                    End If
                                End If
                            Next
                        End If
                    Next
                    'update all game objects
                    For i = gameObjects.Count - 1 To 0 Step -1
                        gameObjects(i).OnUpdate(Me)
                    Next
                    'render the game
                    graphicsBuffer.Graphics.Clear(Color.Black)
                    If GameMap IsNot Nothing Then GameMap.OnRender(Me, graphicsBuffer.Graphics)
                    Dim zorderObjects = (From obj In gameObjects Where obj.Sprite IsNot Nothing Order By obj.ZOrder Descending)
                    For i = zorderObjects.Count - 1 To 0 Step -1
                        zorderObjects(i).OnRender(Me, graphicsBuffer.Graphics)
                    Next
                    graphicsBuffer.Render()
                    'update keyboard input
                    Input.Update()
                    'execute an async delay to make the game loop run asynchronously which keeps the form active
                    Await Task.Delay(1)
                Loop
            End If
        End Function
    
        'provide a method to stop the game
        Public Sub [Stop]()
            _IsRunning = False
        End Sub
    End Class
    
    'define a simple tiled-background map object
    Public Class GameMap
        Public Property TileSprite As Sprite
    
        Public Overridable Sub OnRender(e As GameEngine, gfx As Graphics)
            For y = 0 To e.WindowSize.Height - 1 Step TileSprite.Bounds.Height
                For x = 0 To e.WindowSize.Width - 1 Step TileSprite.Bounds.Width
                    Dim dstBounds As New RectangleF(x, y, TileSprite.Bounds.Width, TileSprite.Bounds.Height)
                    gfx.DrawImage(TileSprite.SpriteSheet, dstBounds, TileSprite.Bounds, GraphicsUnit.Pixel)
                Next
            Next
        End Sub
    End Class
    
    'define the base game object from which all game actors and elements are made
    Public Class GameObject
        'objects with collision will be assigned a collider
        Public Property Collider As CircleCollider
        'all objects have a position
        Public Property Position As PointF
        'all objects face an angle in degrees
        Public Property FacingAngle As Single
        'moving objects have a speed they move at
        Public Property Speed As Single
        'visible objects will be assigned a sprite
        Public Property Sprite As Sprite
        'drawn items are sorted by z-order, descending
        Public Property ZOrder As Integer
        'used by the engine to ensure an object instance is initialized exactly one time
        Public ReadOnly Property IsInitialized As Boolean
    
        Public Overridable Sub OnInitialize(e As GameEngine)
            'override to provide the initial configuration of a game object instance
            _IsInitialized = True
        End Sub
    
        Public Overridable Function OnCollision(e As GameEngine, other As GameObject) As Boolean
            'override to handle collison events
            'indicate whether or not the object was destroyed by the collision and removed from the game engine
            Return False
        End Function
    
        Public Overridable Sub OnRender(e As GameEngine, gfx As Graphics)
            'default drawing for rotated, non-scaling sprites
            gfx.TranslateTransform(Position.X, Position.Y)
            gfx.RotateTransform(MathF.WrapDegrees(FacingAngle + MathF.RIGHT_ANGLE))
            gfx.TranslateTransform(-Position.X, -Position.Y)
            Dim dstBounds = New RectangleF(Position.X - Sprite.Bounds.Width / 2.0!, Position.Y - Sprite.Bounds.Height / 2.0!, Sprite.Bounds.Width, Sprite.Bounds.Height)
            gfx.DrawImage(Sprite.SpriteSheet, dstBounds, Sprite.Bounds, GraphicsUnit.Pixel)
            gfx.ResetTransform()
        End Sub
    
        Public Overridable Sub OnUpdate(e As GameEngine)
            'override in derived classes to add behavior code
        End Sub
    End Class
    
    'define a sprite as an image and a bounding rectangle within the image
    Public Class Sprite
        Public Property SpriteSheet As Image
        Public Property Bounds As RectangleF
    End Class
    
    'Circular collider for effecient collision detection
    Public Class CircleCollider
        'owning game object
        Public ReadOnly GameObject As GameObject
        'offset from center of game object
        Public Origin As PointF
        'radius of circle from origin
        Public Radius As Single
    
        Public Sub New(obj As GameObject)
            GameObject = obj
        End Sub
    
        Public Function CollidesWith(other As CircleCollider) As Boolean
            'collider position must be offset by owner position and rotation
            Dim m As New Drawing2D.Matrix
            m.Translate(GameObject.Position.X, GameObject.Position.Y)
            m.Rotate(GameObject.FacingAngle)
            Dim o1 = {Origin}
            m.TransformPoints(o1)
            'repeat process for other collider
            m.Reset()
            m.Translate(other.GameObject.Position.X, other.GameObject.Position.Y)
            m.Rotate(other.GameObject.FacingAngle)
            Dim o2 = {other.Origin}
            m.TransformPoints(o2)
            'compare collider distances
            Return MathF.Distance(o1(0), o2(0)) <= Radius + other.Radius
        End Function
    End Class
    
    'Synchronized game keyboard input state
    Public Class GameInput
        'hold the keyboard state from the previous frame
        Private lastKeyState As New Dictionary(Of Keys, Boolean)
        'hold the keyboard state for the current frame
        Private currentKeyState As New Dictionary(Of Keys, Boolean)
    
        Public Function IsDown(key As Keys) As Boolean
            If Not currentKeyState.ContainsKey(key) Then Return False
            Return currentKeyState(key)
        End Function
    
        Public Sub SetKeyState(key As Keys, pressed As Boolean)
            currentKeyState(key) = pressed
        End Sub
    
        Public Function WasPressed(key As Keys) As Boolean
            If Not currentKeyState.ContainsKey(key) Then Return False
            Return currentKeyState(key) = False AndAlso lastKeyState(key) = True
        End Function
    
        Public Sub Update()
            For Each k As Keys In currentKeyState.Keys
                lastKeyState(k) = currentKeyState(k)
            Next
        End Sub
    End Class
    
    'Game execution timing mechanism 
    Public Class GameClock
        Public ReadOnly Property LastFrame As Single
        Public ReadOnly Property Elapsed As Single
    
        Private timer As New Stopwatch
    
        Public Sub Update()
            timer.Stop()
            _LastFrame = CSng(timer.Elapsed.TotalSeconds)
            _Elapsed += _LastFrame
            timer.Restart()
        End Sub
    End Class
    #End Region
    
    #Region " Math Helper "
    'Static Math Helper Functions
    Public NotInheritable Class MathF
        Public Const HALF_CIRCLE As Single = 180.0!
        Public Const RIGHT_ANGLE As Single = 90.0!
        Public Const PI As Single = 3.14159274!
        Public Const TWO_PI As Single = PI * 2.0!
    
        Public Shared Function Cos(ByVal radians As Single) As Single
            Return CSng(Math.Cos(CDbl(radians)))
        End Function
    
        Public Shared Function DegreesToRadians(ByVal degrees As Single) As Single
            Return degrees * (PI / HALF_CIRCLE)
        End Function
    
        Public Shared Function Distance(a As PointF, b As PointF) As Single
            Return MathF.Sqrt(MathF.Square(b.X - a.X) + MathF.Square(b.Y - a.Y))
        End Function
    
        Public Shared Function GetPositionToward(ByVal source As PointF, ByVal angle As Single, ByVal distance As Single) As PointF
            angle = DegreesToRadians(angle)
            Return source + New SizeF(MathF.Cos(angle) * distance, MathF.Sin(angle) * distance)
        End Function
    
        Public Shared Function RadiansToDegrees(ByVal radians As Single) As Single
            Return radians * (HALF_CIRCLE / PI)
        End Function
    
        Public Shared Function Sin(ByVal radians As Single) As Single
            Return CSng(Math.Sin(CDbl(radians)))
        End Function
    
        Public Shared Function Sqrt(ByVal value As Single) As Single
            Return CSng(CDbl(value) ^ 0.5)
        End Function
    
        Public Shared Function Square(ByVal value As Single) As Single
            Return value * value
        End Function
    
        Public Shared Function WrapDegrees(degrees As Single) As Single
            Return RadiansToDegrees(WrapRadians(DegreesToRadians(degrees)))
        End Function
    
        Public Shared Function WrapRadians(ByVal radians As Single) As Single
            While radians < -PI
                radians += TWO_PI
            End While
            While radians > PI
                radians -= TWO_PI
            End While
            Return radians
        End Function
    
        Protected Sub New()
        End Sub
    End Class
    #End Region
    

    I hope this demonstrates the basics of a game engine clearly enough that you can use it as a reference model for building your own game engine implementation.  There are a lot of possible variances of the approaches used in this example and there will likely be need for optimization, depending on how you expand upon the base example.  But at a high level, this represents the various steps and stages that your code should go through to execute a game smoothly in terms of both performance and logic behavior.

    Let me know if you have any questions about the "why" or "how" of anything in the code.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    • Marked as answer by Waliur Rahman Sunday, March 19, 2017 1:38 PM
    Saturday, March 18, 2017 8:30 PM
    Moderator

All replies

  • Unfortunately MSDN says I cant send screenshots nor anything unto my account has been verified??

    If you want to see the whole code or screenshots then post your email and I'll forward it to you or ill post the whole code here. 

    Thursday, March 16, 2017 8:34 PM
  • Meanwhile I'm going to experiment using a button to select and see If i can approach a solution because i've spent hrs on this or ill go for the last solution to leave my screen and think on it. 
    Thursday, March 16, 2017 8:36 PM
  • Additional information: Unable to cast object of type 'Sprite' to type 'System.IConvertible'.

    You should indicate what you expect that code to do. That line currently is "compare the second sprite in the list to the number 10, and put the result in the (new) integer 'hp'".  Normally the result of a comparison would be a Boolean, not an integer, but why are you comparing a sprite to 10?  If the Sprite you are using is the Direct3D Sprite it cannot be compared to 10.  If it's some other variety of sprite you should should make that clear. I suspect that you actually intend something entirely different.

    Thursday, March 16, 2017 9:05 PM
  • I wish I can show you a screenshot to give you an idea of what I am trying to do...

    Sprite is a class that I have made so that I can apply it so I declared variables pic as a picturebox for instance. 

    Thanks for the indication about compare two sets of sprites. 

    Pretend Sprite(1) is "Tank A", I have assigned that with 10 hp then assign Sprite(2) is "Tank B" which is assigned as 10 attack points. I want to get the code to select "Tank A" to attack "Tank B" to see if the attack points are more than or equal to the HP and if so then Tank A is destroyed else it does HP - the attack points if less than. 

    To get back to your info its not a direct3d sprite.

    Private Class Sprite
            Public Pic As PictureBox
            Public ColRow As Point
            Public Steps As Integer = -1    '-1 = unlimited move
            Public Visible As Integer = 2   '0 = not visible  1= Frozen  2=Active   
        End Class
    
        Private Sprites As New List(Of Sprite)
        Private MouseDownSprite As Sprite
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            DoubleBuffered = True
    
            For i = 1 To 3
    
                Dim pic = New PictureBox()
                With pic
                    .Name = "Pic " & i.ToString
                    .Size = GridSize
                    .BackgroundImageLayout = ImageLayout.Stretch
                    .BackgroundImage = Image.FromFile("C:\Users\BusinessOffice1Room\Documents\Waliur File\A Level\Computer Science\Coursework\Work In progression\Elements + Stage 2 Designs\Tanks\" & i.ToString & ".png")
                    Me.Controls.Add(pic)
                    AddHandler .MouseDown, AddressOf pics_MouseDown
                    AddHandler .MouseMove, AddressOf pics_MouseMove
                    AddHandler .MouseUp, AddressOf pics_MouseUp
                End With
    
                Dim spt As New Sprite
                spt.Pic = pic
                spt.ColRow = New Point(i, 0)
                Sprites.Add(spt)
    
            Next
    
            Sprites(1).Visible = 2  'frozen
            Sprites(2).Steps = 2
    
    
        End Sub

    Thursday, March 16, 2017 9:24 PM
  • Sprite is a class that I have made so that I can apply it so I declared variables pic as a picturebox for instance.

    A screenshot is not relevant - the problem is in the code.

    "Pretend Sprite(1) is "Tank A", I have assigned that with 10 hp".  How did you do that?  I can't see anything in the class definition that would allow you to do that.   But whatever you did to do that gives you the clue you need to get that value back.


    • Edited by AcamarMVP Thursday, March 16, 2017 9:31 PM
    Thursday, March 16, 2017 9:29 PM
  • Ahh ok you can visualize my problem glad to know. 

    I realise that other code might not work but it is to do with the select functionality. I have got a start here. 

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim hp As Integer = Convert.ToInt32(Sprites(1)) = 10
            Dim cp As Integer = Convert.ToInt32(Sprites(2)) = 10
            Dim Destroy As Boolean
    
            If Sprites(2).Pic.Select(cp) <= Sprites(1).Pic.Select(hp) Then
                Destroy = True
                MsgBox("Tank is RIP")
            Else
                hp = hp - cp
            End If
        End Sub
    Im just testing with this first.

    Thursday, March 16, 2017 9:33 PM
  • I think I get what you are trying to get me to see so what I have done is use sprite to get a png to open up and Im converting it to an integer to assign hp and cp to it. Am I right?
    Thursday, March 16, 2017 9:34 PM
  • Dim hp As Integer = Convert.ToInt32(Sprites(1)) = 10

    Please explain what you expect this line of code to do, because I suspect that you intend something entirely different than what it is actually doing.

    Thursday, March 16, 2017 9:37 PM
  • I see the root of the problem might be the declared variables because as soon as i start the program that's where the program halts to 
    Thursday, March 16, 2017 9:38 PM
  • What I want to do specifically is the image within sprite, I want to assign the image to set healthpoints and attack points to it. 
    Thursday, March 16, 2017 9:39 PM
  • Ill look at some code alternatives to sort the declared variable solution on my side and see If I come up with a new solution.
    Thursday, March 16, 2017 9:48 PM
  • Thursday, March 16, 2017 9:50 PM
  • What I want to do specifically is the image within sprite, I want to assign the image to set healthpoints and attack points to it. 
    The image or the sprite?  If you want your sprite to have health points or attack points then you need properties that represents that feature.  It seems that your statement "I have assigned that with 10 hp" is not correct - that you haven't yet succeeded in assigning 10 as the value.  You can't just assume that a piece of code works as expected - you must test each step of the way.  In this case, you need to test that you really have assigned those 10 points, and that's the bit that I can't see that you have done, because I can't see any way that a sprite can have any 'health' or 'attack' values.  I would strongly recommend taking the time to create a little 'sprite status' display on your form.  Each time you think you have set something about the sprite, show its status, so you can confirm that you really did what you think you did.  It seems like pointless extra effort now, but it will save hours of debugging later on.
    Thursday, March 16, 2017 9:51 PM
  • Sorry If didn't clarify enough its my fault there. The sprite as you know is a class which I have declared within it pic as picturebox and did a code where it imports given images into the game grid.

    Sprite represents multiple picturebox as seen with this code 

    For i = 1 To 3
    
    Dim pic = New PictureBox()
                With pic
                    .Name = "Pic " & i.ToString
                    .Size = GridSize
                    .BackgroundImageLayout = ImageLayout.Stretch
                    .BackgroundImage = Image.FromFile("C:\Users\BusinessOffice1Room\Documents\Waliur File\A Level\Computer Science\Coursework\Work In progression\Elements + Stage 2 Designs\Tanks\" & i.ToString & ".png")
                    Me.Controls.Add(pic)
                    AddHandler .MouseDown, AddressOf pics_MouseDown
                    AddHandler .MouseMove, AddressOf pics_MouseMove
                    AddHandler .MouseUp, AddressOf pics_MouseUp
                End With
    the background image just selects the files that I have referred to in the for loop. 


    Thursday, March 16, 2017 9:57 PM
  • Thanks for that link I'm gonna read through it before moving to the next stage of interacting  sprites to attack each other. Maybe I need that step back and maybe this link you sent me will clear things out to me in english haha rather than in code
    Thursday, March 16, 2017 10:09 PM
  • the background image just selects the files that I have referred to in the for loop. 

    That's interesting but nothing to do with your problem. You are trying to give a sprite health points and attack points, but your sprite class has no facility for assigning, storing or retrieving those values.  That's the problem you need to address and the task you need to focus on.  Then you can look at how to do the assignment of the values, and how to compare the values between sprites.

    Thursday, March 16, 2017 10:10 PM
  • Sounds good ill msg on further questions but for now ill read what tommy sent
    Thursday, March 16, 2017 10:16 PM
  • I thought of a good idea where I use a data storage (access database) where I store the attack points and health points on there and then implement it to my sprites like that, an idea which I will put to the test. I just hope this does the trick since you cant declare a sprite with integers.

    WRA

    Friday, March 17, 2017 9:15 AM
  •  Why not just do as has been recommended and add a Health Power and Attack Power to the Sprite class itself. I would recommend making the members of this class all Public Properties instead of just Public variables but,  just as an example...

        Private Class Sprite
            Public Pic As PictureBox
            Public ColRow As Point
            Public Steps As Integer = -1    '-1 = unlimited move
            Public Visible As Integer = 2   '0 = not visible  1= Frozen  2=Active   
            Public Health As Integer
            Public Attack As Integer
        End Class

     Then you can get or set the Health and Attack power of any Sprite directly from the Sprite.


    If you say it can`t be done then i`ll try it

    Friday, March 17, 2017 9:29 AM
  • I just hope this does the trick since you cant declare a sprite with integers.

    You CAN have health and attack associated with your sprites.  Exactly like you already have visibility and movement associated with your sprites.

    How you store your sprite information is a completely different topic that is not relevant to the current issue.  You need to focus on the problem you are currently addressing, and not wander off on tangents.

    Friday, March 17, 2017 10:17 AM
  • I thought of a good idea where I use a data storage (access database) where I store the attack points and health points on there and then implement it to my sprites like that, an idea which I will put to the test. I just hope this does the trick since you cant declare a sprite with integers.

    WRA

    Wali,

    LOL. Well this is important so lets beat on it some more...

    Just because you dont understand it does not mean it cant be done. Where did you read you cant declare an integer for a Sprite Class? Stick to facts you read, not ones you make up because you dont understand something.

    First off it is a custom class so you can define whatever variables you want more or less. The word Sprite is just the name. It could be named tommysclass or mogumbo.

    Second off, if you dont know how to do something it does not mean you need to revert back to something you know how to do.

    Third off, using a database for this would be like using a 40 feet semi trailer to carry two six packs of beer.

    Fourth off, here is an example. See how the y variable is shown as an error because it is not declared like x. See the red squiggle line showing an error?

    In this image of the class the declaration for MyInteger is commented out and therefore gives an error as shown when one tries to use that variable since it does not exist.

    When the declare for myinteger is added to the class it now works properly.

    Your error message is slightly different because you have a llst of the class.

    Fifth off I am still learning classes too so don't feel left out.

    PS I used a structure but I meant CLASS. In this case the Structure is the same just put the word class where it says structure.

    PSS The whole reason for making a class in this case is to group data that is the same into a handy object that contains the data for each thing that is the same.

    Kinda like beer. There is the variable beer, it can be amber colored, or brown, or today even green. Then there is the Can and its image on the label. So we have beer color, beer can, beer can image as variables.

    Now we can use those and drag along the single variables for each can or we can collect them into an object or package like a six pack of cans of beer. Then can is like the class structure and the six pack is like a list of the can class.

    :)

    Ummm, thirsty?



    Friday, March 17, 2017 12:22 PM
  • Umm, beer...

    Public Class Form2
        Private Class BeerCan
            Public Name As String
            Public MaterialType As Integer '1= aluminum  2 = glass
            Public Color As Color
            Public Flavor As String
        End Class
    
        Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Dim BeerCase As New List(Of List(Of BeerCan))
    
            For j = 1 To 4
                Dim sp As New List(Of BeerCan)
                For i = 1 To 6
                    Dim bc As New BeerCan
                    With bc
                        .Name = "Six Pack " & j.ToString & " - Beer Can " & i.ToString
                        .MaterialType = 1
                        .Color = Color.Brown
                        .Flavor = "Brown Ale"
                    End With
    
                    sp.Add(bc)
                Next
                BeerCase.Add(sp)
            Next
        End Sub
    End Class

    Friday, March 17, 2017 1:45 PM
  • Alright thanks for the hinters Iron. Before I get anybody else to help me I wanna try work this out otherwise I can't learn from these errors and I might become dependent rather than independent. Even though at times there are occasions where yes help is needed then there are simple things which is frustrating that I can't figure out but it took my friend who has more experience a minute to solve. 

    WRA

    Friday, March 17, 2017 3:14 PM
  • I see so there isn't a need for another data storage it is within the class of sprite which is the focus. 

    WRA

    Friday, March 17, 2017 3:15 PM
  • LOOOOL you just making me laugh but yeah I get the point you are taking here. I am trying to avoid a problem that I can tackle yet im going for something I already familiarised with myself though I should challenge myself

    WRA

    Friday, March 17, 2017 3:18 PM
  • Umm, beer...

    Public Class Form2
        Private Class BeerCan
            Public Name As String
            Public MaterialType As Integer '1= aluminum  2 = glass
            Public Color As Color
            Public Flavor As String
        End Class
    
        Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Dim BeerCase As New List(Of List(Of BeerCan))
    
            For j = 1 To 4
                Dim sp As New List(Of BeerCan)
                For i = 1 To 6
                    Dim bc As New BeerCan
                    With bc
                        .Name = "Six Pack " & j.ToString & " - Beer Can " & i.ToString
                        .MaterialType = 1
                        .Color = Color.Brown
                        .Flavor = "Brown Ale"
                    End With
    
                    sp.Add(bc)
                Next
                BeerCase.Add(sp)
            Next
        End Sub
    End Class

    With this:

    Public MaterialType As Integer '1= aluminum  2 = glass

    You could set that up as an Enum (which is an integer).


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Friday, March 17, 2017 3:28 PM
  • Im going to first test using a button so as soon as I select it then one sprite will attack another sprite, once that is done then I'll proceed to carrying the functionality where I mouseclick it instead. 

    WRA

    Friday, March 17, 2017 3:41 PM
  • I've written about this stuff countless times... you might want to read the top portion of this article to get an understanding of how your current approach is both very common for beginners, and generally unworkable in the end.  The article is getting dated, but the top commentary before the code starts is still relevant; just read up to the example code and stop there.

    Terminology is often an issue and we should clear that up first.  Technically a Sprite is just a bitmap image and is often only a part of some larger image file, or SpriteSheet.  But in game engine terms, a Sprite may represent a complete game object including image(s), properties, and functionality.  For this reason, it is often better to think of the term Sprite as being a simple wrapper for an image file and a bounding rectangle within that file (that is, a Sprite Sheet and the bounds of the individual sprite image within the sheet).  You then define a GameObject class which can have a Sprite property, a Location property, Update() and Render/Draw() methods, and whatever else applies to all GameObjects in your game.

    It is common to then create specific game objects by inheriting the base GameObject class.  For example, you might have a Tank class which inherits from GameObject, thereby having a Sprite and Location property, to which you add AttackPower and Health properties.

    A game is a special kind of application.  While a very simple game (think Solitaire or Mine Sweeper) might get away with using a standard event-driven program model, most games require a single game loop to iterate over the entire game state in a consistent manner.  In general, a game loop should, on each iteration:

    1. Update the GameTime, calculating the last frame time
    2. Calculate collisions for GameObjects based on their position as of the last frame
    3. Update all GameObjects
    4. Render/draw all updated GameObjects for the current frame

    There are a number of ways to go about designing and implementing a game loop, and the decisions all rest upon the kind of game you are making and the functionality/performance it will require.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Friday, March 17, 2017 4:19 PM
    Moderator
  • I finally have lift off :) I have tested with a button where it will attack one sprite against another to see if it is still standing and it does but I need to see whether I could take it down and write code where once it goes down the sprite is removed. perhaps along the lines Sprites(1).Remove

    WRA

    Friday, March 17, 2017 4:32 PM
  • I finally have lift off :) I have tested with a button where it will attack one sprite against another to see if it is still standing and it does but I need to see whether I could take it down and write code where once it goes down the sprite is removed. perhaps along the lines Sprites(1).Remove

    WRA

    Sprites(1).Remove

    So you'd want to remove the second one then? If you mean the first one, that would be at the index 0, not 1.

    *****

    Did you read anything that Reed wrote? He's done quite a lot with game objects, game engines, designing games, etc..


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Friday, March 17, 2017 4:50 PM
  •  Private Class Sprite
            Public Pic As PictureBox
            Public ColRow As Point
            Public Steps As Integer = -1    '-1 = unlimited move
            Public Visible As Integer = 2   '0 = not visible  1= Frozen  2=Active   
            Public HP As Integer
            Public AP As Integer
        End Class

    I have assigned the sprites with an integer as so.

            Sprites(1).HP = 10
            Sprites(2).HP = 10
    
    
            Sprites(1).AP = 10
            Sprites(2).AP = 10

    These have been put in the form1_load area 

    Then here is the button to determine whether sprite 1 will stay standing or not. 

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            If Sprites(1).HP = 0 Then
                Sprites(1).HP = Sprites(1).HP - Sprites(2).AP
                MsgBox("Murked")
            Else
                MsgBox("Still standing")
            End If
    
        End Sub
    Have I done something wrong here such as put the sprites set HP in the wrong form load and rather it should be in the class sprite


    WRA

    Friday, March 17, 2017 4:50 PM
  • I figured out what was up with the sprites assigned with HP: I check to see if it is displaying a specific number by showing it in a label and it comes up with 0 so there is something wrong with the "sprites(1).HP = 10" 

    WRA

    Friday, March 17, 2017 6:56 PM
  • I see but the thing is i indicated in the for statement 1 to 3 which is basically the name of my png files you see

    WRA

    Friday, March 17, 2017 7:01 PM
  • I see but the thing is i indicated in the for statement 1 to 3 which is basically the name of my png files you see

    WRA

    Its the name of the file but it is not the index to the list. The list index starts at zero.

    So list(0) is the first item you add to the list, list(1) second and list(2) third.

    PS As Frank said.

    Show the entire code you have.


    And which line you get the error on.
    Friday, March 17, 2017 7:11 PM
  • Alright I show it let me just restore it to its original form 

    WRA

    Public Class Form1
        Private GridColRows As New Point(5, 5)
        Private GridRect As Rectangle
        Private GridSize As Size
        Private MouseMovingColRow, PicColRow, MouseDownPicLocation, MouseDownLocation As Point
    
        Private Class Sprite
            Public Pic As PictureBox
            Public ColRow As Point
            Public Steps As Integer = -1    '-1 = unlimited move
            Public Visible As Integer = 2   '0 = not visible  1= Frozen  2=Active   
            Public AP As Integer
            Public HP As Integer = 10
        End Class
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Sprites(1).HP = 10
            Sprites(2).HP = 100
            Sprites(1).AP = 10
            Sprites(2).AP = 100
            If Sprites(1).HP <= 0 Then
                Sprites(1).HP = Sprites(1).HP - Sprites(2).AP - 10
                Sprites(1).HP = Label1.Text
                MsgBox("Murked")
            Else
                MsgBox("Still standing")
            End If
        End Sub
    
        Private Sprites As New List(Of Sprite)
        Private MouseDownSprite As Sprite
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            DoubleBuffered = True
    
            For i = 1 To 3
    
                Dim pic = New PictureBox()
                With pic
                    .Name = "Pic " & i.ToString
                    .Size = GridSize
                    .BackgroundImageLayout = ImageLayout.Stretch
                    .BackgroundImage = Image.FromFile("C:\Users\BusinessOffice1Room\Documents\Waliur File\A Level\Computer Science\Coursework\Work In progression\Elements + Stage 2 Designs\Tanks\" & i.ToString & ".png")
                    Me.Controls.Add(pic)
                    AddHandler .MouseDown, AddressOf pics_MouseDown
                    AddHandler .MouseMove, AddressOf pics_MouseMove
                    AddHandler .MouseUp, AddressOf pics_MouseUp
                End With
    
                Dim spt As New Sprite
                spt.Pic = pic
                spt.ColRow = New Point(i, 0)
                Sprites.Add(spt)
    
            Next
    
            Sprites(1).Visible = 2  'frozen
            Sprites(2).Steps = 2
    
    
            Label1.Text = Sprites(1).HP
            Label2.Text = Sprites(1).AP
    
            Form1_Resize(1, Nothing)
        End Sub
    
    
    
        Private Sub pics_MouseDown(ByVal obj As Object, ByVal e As MouseEventArgs)
            If e.Button = MouseButtons.Left Then
                For Each spt As Sprite In Sprites
                    If spt.Pic Is DirectCast(obj, PictureBox) Then
                        If spt.Visible = 2 Then
                            MouseDownPicLocation = spt.Pic.Location
                            MouseDownLocation = e.Location
                            MouseDownSprite = spt
                            spt.Pic.BringToFront()
                        Else
                            MouseDownSprite = Nothing
                        End If
                        Exit For
                    End If
                Next
            End If
        End Sub
    
        Private Sub pics_MouseMove(ByVal obj As Object, ByVal e As MouseEventArgs)
            If e.Button = MouseButtons.Left AndAlso MouseDownSprite IsNot Nothing Then
                SetSpriteLocation(e.Location, MouseDownSprite)
                MouseDownPicLocation = MouseDownSprite.Pic.Location
            End If
        End Sub
    
        Private Sub pics_MouseUp(ByVal obj As Object, ByVal e As MouseEventArgs)
            If e.Button = MouseButtons.Left AndAlso MouseDownSprite IsNot Nothing Then
                SetSpriteLocation(e.Location, MouseDownSprite)
                MouseDownSprite.ColRow = PicColRow
            End If
        End Sub
    
        Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
            With e.Graphics
                .Clear(Color.White)
                .FillRectangle(Brushes.Blue, GridRect)
    
                Using p1 As New Pen(Color.Black, 1)
                    For x = GridRect.X To GridRect.X + GridRect.Width Step GridSize.Width
                        .DrawLine(p1, x, GridRect.Y, x, GridRect.Y + GridRect.Height)
                    Next
                    For y = GridRect.Y To GridRect.Y + GridRect.Height Step GridSize.Height
                        .DrawLine(p1, GridRect.X, y, GridRect.X + GridRect.Width, y)
                    Next
                End Using
            End With
        End Sub
    
        Private Sub Form1_Resize(sender As Object, e As EventArgs) Handles Me.Resize
            Dim border As Integer = 0
            Dim header As Integer = 40
            Dim h As Integer = ClientRectangle.Height - (header + border)
            If h < 10 Then h = 10
            GridRect = New Rectangle(border, header, ClientRectangle.Width - (2 * border), h)
            GridSize = New Size(CInt(GridRect.Width / GridColRows.X), CInt(GridRect.Height / GridColRows.Y))
            DrawSprites()
            Invalidate()
        End Sub
    
        Private Sub DrawSprites()
            For Each spt In Sprites
                If spt.Visible > 0 Then spt.Pic.Visible = True
                spt.Pic.ClientSize = GridSize
                spt.Pic.Location = GetGridRectFromColRow(spt.ColRow).Location
            Next
    
        End Sub
    
    
        Private Function GetGridRectFromColRow(thisColRow As Point) As Rectangle
            'make the rectangle for the grid square at col row
            GetGridRectFromColRow = New Rectangle(GridRect.X + (thisColRow.X * GridSize.Width),
                        GridRect.Y + (thisColRow.Y * GridSize.Height), GridSize.Width, GridSize.Height)
        End Function
    
        Private Function GetColRowFromPoint(thisPt As Point) As Point
            'convert pixel location to grid cols and rows
            GetColRowFromPoint = New Point(CInt(Math.Floor((thisPt.X - GridRect.X) / GridSize.Width)),
                            CInt(Math.Floor((thisPt.Y - GridRect.Y) / GridSize.Height)))
    
            If GetColRowFromPoint.X < 0 Then GetColRowFromPoint.X = 0
            If GetColRowFromPoint.X > GridColRows.X - 1 Then GetColRowFromPoint.X = GridColRows.X - 1
            If GetColRowFromPoint.Y < 0 Then GetColRowFromPoint.Y = 0
            If GetColRowFromPoint.Y > GridColRows.Y - 1 Then GetColRowFromPoint.Y = GridColRows.Y - 1
        End Function
    
        Private Sub SetSpriteLocation(thisMovePt As Point, spt As Sprite)
            'snap the picturebox to the col row on the grid at mouse pointer movept in pixels
            Dim movept As New Point(MouseDownPicLocation.X + thisMovePt.X,
                                        MouseDownPicLocation.Y + thisMovePt.Y)
    
            PicColRow = GetColRowFromPoint(movept)
    
            Dim dc As Integer = PicColRow.X - spt.ColRow.X
            Dim dr As Integer = PicColRow.Y - spt.ColRow.Y
            Dim dc2 As Integer = Math.Abs(dc)
            Dim dr2 As Integer = Math.Abs(dr)
    
            If spt.Steps > 0 AndAlso Not spt.Steps = -1 AndAlso dc2 + dr2 > spt.Steps Then
                If dc2 > spt.Steps Then
                    dc2 = spt.Steps * Math.Sign(dc)
                    dr2 = 0
                Else
                    If dr2 > spt.Steps - dc2 Then
                        dr2 = (spt.Steps - dc2) * Math.Sign(dr)
                        dc2 = dc
                    End If
                End If
                PicColRow = New Point(spt.ColRow.X + dc2, spt.ColRow.Y + dr2)
            End If
    
    
            spt.Pic.Location = GetGridRectFromColRow(PicColRow).Location
    
            Refresh()
        End Sub
    End Class
    Important areas to look is from Public Form 1 to end of sub on Button1

    Friday, March 17, 2017 7:15 PM
  • 
    Important areas to look is from Public Form 1 to end of sub on Button1

    Wali,

    Which line is it you see the wrong value on?

    When you respond to a message please be sure to add the persons name or a quote or something to make it clear which message you are responding to if any.


    PS What do you think the value should be?
    Friday, March 17, 2017 7:21 PM
  • Ahh alright like whatsapp so @Tommytwotrain 

    The wrong values I see in there is 

     Sprites(1).HP = 10
            Sprites(2).HP = 100
            Sprites(1).AP = 10
            Sprites(2).AP = 100

    Somehow when I execute the program it doesnt show those values in a label just to test it. 


    WRA

    Friday, March 17, 2017 7:28 PM
  • Apologies this is the code which shows the ammo stored and it indicates 0 

            Label1.Text = Sprites(1).HP
            Label2.Text = Sprites(2).AP

    This is positioned under the form1_load 


    WRA


    Friday, March 17, 2017 7:39 PM
  • Alright ill report back as soon as I see results 

    WRA

    Friday, March 17, 2017 7:48 PM
  • Right I was stepping through the code and it skip through if statement and went right to the else statement to give the answer "Still standing"

    That indicates there maybe something wrong with the If statement or declared variable


    WRA


    Friday, March 17, 2017 7:50 PM
  • Apologies this is the code which shows the ammo stored and it indicates 0 

            Label1.Text = Sprites(1).HP
            Label2.Text = Sprites(2).AP

    This is positioned under the form1_load 


    WRA


    Oh,


    When you do this in the form load:

         Label1.Text = Sprites(1).HP

    That puts the value in the label at the time the line was executed. At that time the value of Sprites(1).HP is zero.

    Then in your button click you have

          Sprites(1).HP = 10

    But that will not affect the value in the label. It remains as set in form load, zero or nothing.

    And then if you keep going

          Sprites(1).HP = Label1.Text

    Will make Sprites(1).HP the value in the label which is zero.

    Put a break point on the first line in the button click and look at the values of all the variable using intellisense (like the beer class image I showed). Then step one line of code execution, look at the values, etc.


    PS Use Option Strict On so Visual Studio points out errors in declarations etc.

    Oh wait the value in the label in formload when you start is 10 as set in the class

    But you see how you end up with zero where I showed?

    Be specific. Exactly which line do you mean you see zero?  :)

    Friday, March 17, 2017 7:59 PM
  • So I declared HP as integer which is assumed as zero while sprite 1 is assigned with HP = 10

    WRA

    Friday, March 17, 2017 8:00 PM
  • @Tommy 

    I put on option strict and shows a red squiggly line right under where I assign 

                Sprites(1).HP = Label1.Text


    WRA

    Friday, March 17, 2017 8:02 PM

  • I put on option strict and shows a red squiggly line right under where I assign 

                Sprites(1).HP = Label1.Text


    WRA

    ...and you don't understand why?

    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Friday, March 17, 2017 8:07 PM
  • Its due to being an implicit version to convert string to integer. 

    WRA

    Friday, March 17, 2017 8:12 PM
  • Its due to being an implicit version to convert string to integer. 

    WRA


    Who are you talking to?

    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Friday, March 17, 2017 8:15 PM
  • @Tommy 

    I put on option strict and shows a red squiggly line right under where I assign 

                Sprites(1).HP = Label1.Text


    WRA

    When you put the mouse point over the red line you get the error shown in a popup, I guess that is Intellisense, and what is the error? Cant convert string to int? Try :

        Sprites(1).HP = CInt(Label1.Text)

    Convert string .text to integer. There is more to this but cint is fine for now. But that's not the problem?

    I have now made the form and run your example it seems to work?

    When I click the button it says "still standing".

    So I am still not sure exactly what you are expecting to happen that does not with the code you show?


    PS Don't you need to subtract points in both sides of the if? Or is that the problem?
    Friday, March 17, 2017 8:17 PM
  • @tommy 

    what Im basically trying to do is the HP from sprite 1 is subtracted by the AP from sprite 2 then it will determine whether the tank is still standing or not.


    WRA

    Friday, March 17, 2017 8:19 PM
  • @Tommy Im gonna keep trying on my side this is a more difficult concept than I thought it would be 

    WRA

    Friday, March 17, 2017 8:33 PM
  • what Im basically trying to do is the HP from sprite 1 is subtracted by the AP from sprite 2 then it will determine whether the tank is still standing or not.

    Can you describe, using plain English and no technical terminology at all, what you intend for this line of code to do:         

     Sprites(1).HP = Sprites(1).HP - Sprites(2).AP - 10

    because I think there might still be the same issue with the forming of expressions that you started the thread with. That code doesn't seem to agree with the description above.

    Then you should look closely at these lines

            Sprites(1).HP = 10
            Sprites(2).HP = 100
            Sprites(1).AP = 10
            Sprites(2).AP = 100
            If Sprites(1).HP <= 0 Then  ...

    and decide why that logic is wrong.

    Friday, March 17, 2017 8:43 PM
  • @Tommy 

    Public Function IsFacing( _ ByRef spr1 As TSPRITE , _ ByRef spr2 As TSPRITE) As Boolean Dim n As Long Dim a As point Dim b As point 'are both sprites in range of each other? If Not Collision(spr1, spr2) Then IsFacing = False Exit Function End IF a.x = spr1.x +spr2.width / 2 a.y = spr1.y + spr1.height / 2 b.x = spr2.x + spr2.width / 2 b.y = spr2.y + spr2.height / 2 select Case spr1.AnimSeq 'Looking up Case 7,0,1 If b.y < a.y Then IsFacing =True 'Looking down Case 5,4,3 If b.y > a.y Then IsFacing = True 'Looking Left Case 6 if b.x < a.x Then IsFacing = True

    	'Looking right
    	Case 2
    		If b.x  > a.x Then IsFacing = True
    	End Select
    
    End Function

    I found this which indicates if the the two sprites are in range 

    https://www.go4expert.com/articles/visual-baisc-rpg-attack-combat-script-t11863/

    Here is the site which i found it one I'm reading through to see if anything useful relating to attacking sprites is found 


    WRA

    Friday, March 17, 2017 8:44 PM
  • @Acamar 

    Pretend Sprite(1) is Building and Sprite(2) is Battle Tank 

    Ok ill try So what I want to do is when I select the Battle Tank declares an attack onto the Building then the stored HP in the building which is at 10 is subtracted by the attack points of the battle tank which results in the building destroyed. 


    WRA

    Friday, March 17, 2017 9:05 PM
  • Pretend Sprite(1) is Building and Sprite(2) is Battle Tank 

    Ok ill try So what I want to do is when I select the Battle Tank declares an attack onto the Building then the stored HP in the building which is at 10 is subtracted by the attack points of the battle tank which results in the building destroyed. 

    That's what you want to do.  But what do you expect that specific bit of code to do?  I think it is this part of your description "the stored HP in the building is reduced by the attack points of the battle tank".  There is nothing in that code that does anything about destroying a building or selecting anything.  When looking at syntax you need to be sure that your attention is on the specific line of code, not the overall task. 

    (I have assumed that you meant to write 'reduced by' and not 'subtracted from', as 'subtracted by' is ambiguous'.)

    That line of code needs to work whatever the current value of the HP of the building is, so the reference to 10 is wrong. Code that matches the amended description is

     Sprites(1).HP = Sprites(1).HP - Sprites(2).AP

    Note that this assumes that the second sprite you created is the building and the third sprite you created is the tank.  If that's not correct you have several adjustments to make.

    Now you can look at the logic of that second piece of code.

    Friday, March 17, 2017 9:26 PM
  • I just wanna ask, does anyone actually clearly see the answer to the problem which I don't see?

    WRA

    Friday, March 17, 2017 9:26 PM
  • Ahh ok thanks for pointing that out, lemme see what I have done there in particular.

    I just thought the method what goes on the left goes on the right too

     Sprites(1).HP = Sprites(1).HP - Sprites(2).AP




    WRA

    Friday, March 17, 2017 9:31 PM
  • I see so the function of the code is correct and the part where I have said

    Sprites(1).HP = 10 and so on, there is something wrong which isn't agree through the rest of the program 


    WRA

    Friday, March 17, 2017 9:36 PM
  • I just thought the method what goes on the left goes on the right too

    The result of this calculation:
        Sprites(1).HP - Sprites(2).AP

    is assigned to the HP value of the second sprite in the list.

    Are you quite sure that the sprites you wanted to refer to are the second in the list (Sprites(1)) and the third one in the list (Sprites(2)), because your other comments seem to indicate that you intended to refer to the first (Sprites(0)) and the second (Sprites(1))?

    Now look at the logic of the other piece of code I posted and decide what is wrong with the logic.

    I think you should set aside considerations of collisions etc until you have got the existing code right.

    Friday, March 17, 2017 9:52 PM
  • I see you are going with the approach it all starts of with 0 then to 2 rather than what I did 1 to 3 which could be the error

    WRA

    Friday, March 17, 2017 9:55 PM
  • Nope that doesn't seem to be the error from what I have just tried it takes me back to square one. 

    WRA

    Friday, March 17, 2017 10:06 PM
  • I see you are going with the approach it all starts of with 0 then to 2 rather than what I did 1 to 3 which could be the error

    Not really.  What you did with

    For i = 1 to 3
       ...
    Next

    will work OK, because you need i values of 1, 2 and 3 for finding the image.  It's any reference to Sprites(n) which has to take account of the fact that the first item you add to a list will be at at index 0, the second item you add will be at index 1, and so on.

    You have wandered so far off the original question that I don't know whether or not that has anything to do with your error, but it does mean that the description of what you want to do does not match the code you have provided.

    Friday, March 17, 2017 10:32 PM
  • Nope that doesn't seem to be the error from what I have just tried it takes me back to square one.

    What change did you make and what is the current error? Did you fix the logic problem in

            Sprites(1).HP = 10
            Sprites(2).HP = 100
            Sprites(1).AP = 10
            Sprites(2).AP = 100
            If Sprites(1).HP <= 0 Then  ...

    Friday, March 17, 2017 10:33 PM
  • Thus far square one shows the same error to before and the logic problem I seem to have not fixed, I somewhat think my logic of things have gone :(

    WRA

    Friday, March 17, 2017 10:40 PM
  • @Iron Razers 

    I've literally been trying as hard as possible to figure out this solution. I didn't think it would be this difficult. 

    If I can't find the issue, Im gonna sleep on it and If you are willing please try find an approach to solve this worst case scenario


    WRA

    Friday, March 17, 2017 10:57 PM
  •  Private Class Sprite
            Public Pic As PictureBox
            Public ColRow As Point
            Public Steps As Integer = -1    '-1 = unlimited move
            Public Visible As Integer = 2   '0 = not visible  1= Frozen  2=Active   
            Public HP As Integer
            Public AP As Integer
        End Class

    I have assigned the sprites with an integer as so.

            Sprites(1).HP = 10
            Sprites(2).HP = 10
    
    
            Sprites(1).AP = 10
            Sprites(2).AP = 10

    These have been put in the form1_load area 

    Then here is the button to determine whether sprite 1 will stay standing or not. 

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            If Sprites(1).HP = 0 Then
                Sprites(1).HP = Sprites(1).HP - Sprites(2).AP
                MsgBox("Murked")
            Else
                MsgBox("Still standing")
            End If
    
        End Sub
    Have I done something wrong here such as put the sprites set HP in the wrong form load and rather it should be in the class sprite


    WRA

    These are both wrong:

            If Sprites(1).HP <= 0 Then
                Sprites(1).HP = Sprites(1).HP - Sprites(2).AP - 10
                Sprites(1).HP = Label1.Text
                MsgBox("Murked")
            Else
                MsgBox("Still standing")
            End If
            If Sprites(1).HP = 0 Then
                Sprites(1).HP = Sprites(1).HP - Sprites(2).AP
                MsgBox("Murked")
            Else
                MsgBox("Still standing")
            End If

    In both cases, you are only going to execute the code to reduce Sprite(1).HP if it is already at zero!  That doesn't make sense.  You want to reduce the HP if the HP is NOT zero - if the HP is zero, the object should already be destroyed and should no longer be a viable target for another attack.

            Sprites(1).HP = Sprites(1).HP - Sprites(2).AP       
            If Sprites(1).HP <= 0 Then
                MsgBox("Murked")
                'remove sprite from list
            Else
                MsgBox("Still standing")
            End If


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"


    Friday, March 17, 2017 11:17 PM
    Moderator
  • Also to mention the others have attempted such as Tommy, Acamar and Frank. 

    WRA

    Friday, March 17, 2017 11:25 PM
  • @Iron Razers 

    I've literally been trying as hard as possible to figure out this solution. I didn't think it would be this difficult. 

    If I can't find the issue, Im gonna sleep on it and If you are willing please try find an approach to solve this worst case scenario


    WRA

     Without understanding the full context of how you have everything set up in your game and how the game is actually suppose to function (be played),  i really can't give an exact solution.  That would be like me telling you how to play a card game that i have never played before. 

     There are many ways to set everything up for a game and how it will all works together.  I am not trying to be rude by saying this so don't take it wrong but,  i believe you may have taken a bigger bite off the apple than you can chew all at this time.  That is not saying that you can not figure it out but,  you really need to have a good understanding of Classes and how you can use them before tackling most games.  This is not something you will learn over night though,  it will take time to absorb and understand.

     I think Reed may have pointed out the latest problem with your code in his last post.  However,  you do seem to have jumped around between a few problems within this one topic so, i am not sure exactly which problem you are referring to at this point.


    If you say it can`t be done then i`ll try it

    Saturday, March 18, 2017 10:56 AM
  • I see. Ok I'll specify the section of the codes which is the main focus cuz I think I've literally waffled most ppl here. 

        Private Class Sprite
            Public Pic As PictureBox
            Public ColRow As Point
            Public Steps As Integer = -1    '-1 = unlimited move
            Public Visible As Integer = 2   '0 = not visible  1= Frozen  2=Active   
            Public AP As Integer
            Public HP As Integer
        End Class

    The first part I see within this whole class is correct, I dont see any errors what so ever. 

     Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Sprites(1).HP = 10
            Sprites(2).HP = 100
            Sprites(1).AP = 10
            Sprites(2).AP = 100
            If Sprites(1).HP <= 0 Then
                Sprites(1).HP = Sprites(1).HP - Sprites(2).AP
                MsgBox("Murked")
            Else
                MsgBox("Still standing")
            End If
        End Sub

    This is the second part of the code which is the core of the problem just to clarify. During the step through of the code, it reads from from the Private Sub Button 1 all the way to the start of the If statement.

    It skips over the first statement and reaches the else answer of msgbox("still standing") 

    I'll keep trying from my side to see if there is actually something wrong here with the code written because one who creates code knows the solution but they just dont realise it. 


    WRA

    Saturday, March 18, 2017 1:18 PM
  • I got a question, this is to everybody here. 

    1) Is it possible for a picturebox to be dragged around on a rectangular 30 by 30 or so square grid? 

    thats the first question which im curious about 

    2) If so then will it be possible to assign pictureboxes with integers and try the actions I intended from the sprites and try it with the two pictureboxes instead?


    WRA

    Saturday, March 18, 2017 1:44 PM
  • I see. Ok I'll specify the section of the codes which is the main focus cuz I think I've literally waffled most ppl here. 

        Private Class Sprite
            Public Pic As PictureBox
            Public ColRow As Point
            Public Steps As Integer = -1    '-1 = unlimited move
            Public Visible As Integer = 2   '0 = not visible  1= Frozen  2=Active   
            Public AP As Integer
            Public HP As Integer
        End Class

    The first part I see within this whole class is correct, I dont see any errors what so ever. 

     Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Sprites(1).HP = 10
            Sprites(2).HP = 100
            Sprites(1).AP = 10
            Sprites(2).AP = 100
            If Sprites(1).HP <= 0 Then
                Sprites(1).HP = Sprites(1).HP - Sprites(2).AP
                MsgBox("Murked")
            Else
                MsgBox("Still standing")
            End If
        End Sub

    This is the second part of the code which is the core of the problem just to clarify. During the step through of the code, it reads from from the Private Sub Button 1 all the way to the start of the If statement.

    It skips over the first statement and reaches the else answer of msgbox("still standing") 

    I'll keep trying from my side to see if there is actually something wrong here with the code written because one who creates code knows the solution but they just dont realise it. 


    WRA

    Look at my other reply.... the code marked above is wrong.

    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Saturday, March 18, 2017 1:55 PM
    Moderator
  • The declared area where I have actually assigned it

    WRA

    Saturday, March 18, 2017 1:57 PM
  • I got a question, this is to everybody here. 

    1) Is it possible for a picturebox to be dragged around on a rectangular 30 by 30 or so square grid? 

    thats the first question which im curious about 

    2) If so then will it be possible to assign pictureboxes with integers and try the actions I intended from the sprites and try it with the two pictureboxes instead?


    WRA

    Morning Wali,

    I think we all have seen the problem with your code for days. But we try to teach you to program not just write your code.

    Reed showed you the logical If problem and gave the code to correct it. Did you understand his post?

    You see this question just shows you dont understand the code you have. I wrote the example in the other thread you copied it from. It is a learning example. Meant to show one thing. How to drag a picturebox on a grid with the mouse. Read the rest of the discussion.

    https://social.msdn.microsoft.com/Forums/vstudio/en-US/3401f9f4-bfab-4586-ad47-f80c8bf1f46d/move-a-picturebox-along-a-game-grid?forum=vbgeneral

    When you posted this question and I posted my first answer here I thought you and programmer 10 from the other thread must be the same. But I guess not. Just have the same homework?

    You know we dont know what you know so we have to spend time on the problem before really understanding what you are asking.

    But to answer your question yes you can make a 30x30 grid. You can do it with this example by changing two initial values. But first you have to understand how this example works.

    And finally, dragging pictureboxes is not necessarily the best way to do this but its fine for a starter game to learn how to do the other coding first before getting more complicated.

    We all want to continue with helping but we cant write a game for you or then it becomes our game and you become lost.

    So I think you need to figure out your logical If problem first before you try to move to something more complicated. As the others have said.

    Dont get discouraged. We help lots of beginning gamers and its basically the same thing each time. You have to learn to walk before you can run. And we are only building a birdhouse not a rocketship.

    Saturday, March 18, 2017 1:59 PM
  • @Reed 

    OMG I'm such an idiot for not realizing this thanks REED for pointing this out to me what a fool I am for not actually doing this like damn.

    I manage to get the code to show when the tank is destroyed and when it is not destroyed but I need it to accumulate such as Sprite 2 has 5 attack points but when I click the button twice the sprite 1 still isn't destroyed.


    WRA

    Saturday, March 18, 2017 2:05 PM
  • Ahh I see and who's Programmer10 ??? 

    I manage to figure out what was happening I'll stick with the sprite because I just realised the error in there which I should've saw in the first place


    WRA

    Saturday, March 18, 2017 2:07 PM
  • Yeah I'm getting your approach, your helping my indicate what the errors are within my code rather than spoonfeed the answer, I like that style that you are taking. I know there are times where yes We get stuck at times but like you said I need to figure out the logic within a problem before going onto other complex stuff. 

    WRA

    Saturday, March 18, 2017 2:09 PM
  • Yeah I'm getting your approach, your helping my indicate what the errors are within my code rather than spoonfeed the answer, I like that style that you are taking. I know there are times where yes We get stuck at times but like you said I need to figure out the logic within a problem before going onto other complex stuff. 

    WRA

    Wali,

    There you go. Eureka. Thats how it normally goes.

    The first example in this thread

    https://social.msdn.microsoft.com/Forums/vstudio/en-US/b96c87bc-86b4-47cb-a162-b67082530906/program-that-interacts-png-within-a-windows-form-to-the-game-board-created?forum=vbgeneral

    Does not use pictureboxes. Thats probably where you need to go eventually. Instead of drawing a red square one would draw the images of tanks or cards. But maybe that is for your next project not this one.

    Also that example has the "joy stick" mouse control which could be incorporated to your tanks to say move, or turn an angle. Or not. I can think of many ways.

    But that is the deal... I have 30 years of junk in my toolbox you have what, a month?

    You might want to practice with some more If then else examples etc.

    If you need to save other points then add a variable to your class. If you want to save angles of tanks then add an angle variable. Its all the same. You just need practice with it. Do it over and over with lots of simple examples. Then your brain is wired to do it in a more complex project. You don't have to relearn the basics like how to use Visual Studio because you have practiced it and remember it.

    Put the persons name in the post when you respond so we know what post you mean exactly.

    One needs to be very methodical. Learn something, then keep doing it over and over. Get that thing stuck in your brain. Double check that you are following the rules... then click go. No go? Read the instructions again.

    PS Ever wonder why we answer questions on the forum (besides to show off our work)?

    Practice. Learn something new.

    Saturday, March 18, 2017 2:26 PM
  • Damn I can rotate the angle of the sprites that is actually helpful thanks man. Ill check the link and test it before implementing. 

    WRA

    Saturday, March 18, 2017 2:28 PM
  • Damn I can rotate the angle of the sprites that is actually helpful thanks man. Ill check the link and test it before implementing. 

    WRA


    Well its just a preview. Get the code you already have working and understood before 'implementing" anything new. There are many ways to rotate tanks. I just mentioned that thread to give you some ideas and encouragement that there is plenty of fun to come. But you need to finish the fun you are having now first.
    Saturday, March 18, 2017 2:39 PM
  • @Tommy

    to learn new experiences with VB i suppose. 


    WRA

    Saturday, March 18, 2017 2:39 PM
  • @tommytwotrain

    You are funny, "Fun" that Im having first

     Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Sprites(1).HP = 10
            Sprites(2).HP = 100
            Sprites(1).AP = 10
            Sprites(2).AP = 100
    
            Sprites(1).HP = Sprites(1).HP - Sprites(2).AP
    
            If Sprites(1).HP <= 0 Then
                MsgBox("Murked")
                'remove sprite from list
            Else
                MsgBox("Still standing")
            End If
    End Sub 

    This time I have manage to show that the tank is destroyed, this time it is the other issue where I set the attack points of sprite 2 to less than the heal points of sprite 10 but the tank will still remain standing. 

    Have I made a logic error? or there is something that I'm missing to mention within the piece of code.


    WRA


    Saturday, March 18, 2017 2:51 PM
  • @Everyone 

    I just realised the error like LOOOOL

    it wasn't the error with the code, it was the fact I put the following: 

            Sprites(1).HP = 10
            Sprites(2).HP = 100
            Sprites(1).AP = 10
            Sprites(2).AP = 100

    Inside the button which wasn't suppose to be the case, I was suppose to put that in the Form1_Load 

    so when i set the attack points of sprite 2 as 5, I press the Button once the tank is standing then when I press it again the tank is then destroyed. 

    I can tell all of you right now, your help meant the world because I have fought more than half the battle for my computer science coursework and I am getting much closer to turning into an actual program fully operational. 

    Next thing here I need to do is once the tank is destroyed is to removed the selected sprite that has been attacked out of the form. Disappear for good.

    Then I need to set the position for where they are all positioned and the range that all the sprites can attack from. 

    :) Again thanks yall kudos to Reed for really pointing out where I should focus on the error


    WRA


    Saturday, March 18, 2017 3:09 PM
  • @Reed 

    Is it possible where I select the tank to attack another tank rather than using a button since thats the standard format of most games 


    WRA

    Saturday, March 18, 2017 3:15 PM
  • Acamar is the one who has been spending a lot of time trying to point you toward the those two errors.  I thought you already found the first one with the initialization in the wrong place.  The example I gave you should take care of the damage actually being dealt and the destroyed object being removed from the game.

    As for your question: "Is it possible where I select the tank to attack another tank rather than using a button since thats the standard format of most games "

    You can do anything you want.  I still don't think anyone is clear on how you wanted the user interface to work.  You could respond to a button click, a mouse button, or a key press to cause the tank to attack.  I don't understand how the game is supposed to work... I guess you drag a tank around cells on a map, with some kind of limit as to how many cells you can move per "turn", but I have no idea how you orientate the tank or cause it to fire, or how you know when a turn is over.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Saturday, March 18, 2017 3:26 PM
    Moderator
  • @Reed 

    Is it possible where I select the tank to attack another tank rather than using a button since thats the standard format of most games 


    WRA


    Wali,

    You have to have something that causes an event. Button, mouse click, key press, etc. Events make the code go.

    You have other mouse clicks. There is RMB (Right Mouse Button) it could do something. There is ctrl+LMB. So you can use Alt+RMB for select opponent or whatever.

    I have been thinking that you could have an RMB pop up menu. RMB click the tank, menu pops up, menu has Select Attack Object, Fire, etc. Ctrl_LMB could rotate the tank 45 degrees.

    You can have a toolbar with the various things. Click tank, give it focus, when an object has focus the click the turn angle button, or the select opponent button or the fire button.

    So you need to start designing this interface. What do you need, what will it be, how does it fit what you have etc. But first you need to learn the tools you have. RMB, Alt+RMB, RMB popup menu, combobox control.

    But first you need to understand what you have already. Work on one problem at a time.

    PS Basically anything you see in another game you can do in yours. Only when you get into speed issues with fast running animations and such will you get to any limits using VB code.

    Saturday, March 18, 2017 3:41 PM
  • I have that dealt with there is more to it than that, Im focusing on getting tanks to first interact then building and turrets. 

    In terms how will each player take turns I still gotta deal with that but numero uno is the interaction of the tanks before anything else. 


    WRA

    Saturday, March 18, 2017 3:49 PM
  • You brought a good point perhaps I will keep the button there I might make a sorta controller for each player to use to interact their tanks and use a combobox such as I select from the combobox Sprite(1) then I can move that about to whatever steps I want then I could select from the combobox what tank attacks and an indication in terms of range of what tank to attack. 

    WRA

    Saturday, March 18, 2017 3:53 PM
  • @Tommy

    For now I'm gonna do some of my other school work which I still gotta revise for and at 10 ish or so I'll implement some of the basic stuff such as the sign out feature which I didn't manage to do for the main part of my coursework.

    Then tomorrow I'll move to set a range of the tanks of how many squares they attack from. 


    WRA

    Saturday, March 18, 2017 4:01 PM
  • @Tommy

    For now I'm gonna do some of my other school work which I still gotta revise for and at 10 ish or so I'll implement some of the basic stuff such as the sign out feature which I didn't manage to do for the main part of my coursework.

    Then tomorrow I'll move to set a range of the tanks of how many squares they attack from. 


    WRA

    Wali,

    Ok. I see.

    The article on collisions that you gave is pretty good, a bit old. But, the geometry may need adjusting for the way this example draws using cols and rows. Also I might do it some other way. I am sure the others have better ways?

    Search for more examples using the key words you are learning. Collision detection in games, distance between two points, angle between two points, etc.

    Search this vb forum there are lots of recent things on games and animations.

    Show what you have done if you have more questions. Probably close this thread by marking Razer and Reed's posts as the answer. Give a few helpful marks on the other posts that helped etc. Then post a new question with your latest information and ref this thread if you think its helpful etc.

    Maybe you know all this already. :)

    Saturday, March 18, 2017 5:25 PM
  • I couldn't help myself...

    Here's an example of a 2 player tank game.  It's not precisely the same kind of game you are making so it shouldn't be useful from the perspective of handing it in for an assignment.  However, it does demonstrate all of the key components you would need for your game engine and gives you an example of what all of the necessary objects should look like and how they should work together.

    In this game, two players drive tanks around an open map and try to shoot each other.  Player 1 uses WASD to move and E to shoot while Player 2 uses IJKL to move and U to shoot.  Each tank can take 10 shots before being destroyed.

    The map is drawn with a tiled image, but does not enforce any grid-based movement.  In your own version of the game engine, your game map would define the map cell size and dimensions and your game object would move according to cell positions instead of raw pixel locations.  These are simply adjustments to the behavior logic used in the following example game engine.

    To use the following example, create a new Windows Forms project.  In the solution explorer, right click the project and select Add Folder.  Add a folder named Assets to the project.  Download the following two images and add them to the Assets folder by right clicking the folder and selecting Add Existing Item.

    Tank Game Sprite SheetExplosion Animation Strip

    To ensure compatibility with the code, make sure the file names you save are TankGameSpriteSheet.png and explosion.png.

    After adding the files to the Asset folder, select the first and then go to the properties window and set the Copy to Output Directory property to Copy Always.  Repeat this process for the other file.

    Tank Game Assest Properties

    With the assets in place you can paste the following code over top of the default Form1 code.  I know it looks like a lot of code, but as you read through it you will find that it is really a just a number of relatively small objects.  I've tried to separate the code into regions and add some comments to help explain what things are and what they do.  I hope you'll be able to read over it a couple of times, follow through the logic, and gain an understanding of how a game loop should execute.

    Option Strict On
    
    'example form
    Public Class Form1
        'declare a game engine variable
        Private engine As GameEngine
    
        'execute the Load event handler asynchronously
        Private Async Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            'set the form size and border style
            ClientSize = New Size(800, 600)
            FormBorderStyle = FormBorderStyle.FixedSingle
    
            'create the new game engine instance and load the image assets
            engine = New GameEngine(Me)
            engine.LoadAssets()
    
            'create, configure, and assign the background map
            Dim mapSprite As New Sprite
            mapSprite.SpriteSheet = engine.SpriteSheets("TankGameSpriteSheet")
            mapSprite.Bounds = New RectangleF(192, 0, 96, 96)
            engine.GameMap = New GameMap With {.TileSprite = mapSprite}
    
            'create the two player tanks and add them to the game
            engine.AddObject(New Player1Tank With {.Position = New PointF(50, 100)})
            engine.AddObject(New Player2Tank With {.Position = New PointF(750, 100)})
    
            Try
                'run the game
                Await engine.Run
            Catch ex As Exception
                Stop 'stop here during debugging to examine the error which occured
            End Try
        End Sub
    
        'end the game when the form closes
        Private Sub Form1_Closing(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles Me.Closing
            engine.Stop()
        End Sub
    
        Private Sub Form1_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
            'notify the engine when a key is pressed
            engine.Input.SetKeyState(e.KeyCode, True)
        End Sub
    
        Private Sub Form1_KeyUp(sender As Object, e As KeyEventArgs) Handles Me.KeyUp
            'notify the engine when a key is released
            engine.Input.SetKeyState(e.KeyCode, False)
        End Sub
    
    End Class
    
    #Region " Game Actors (GameObject Instances) "
    
    'Define a base Tank class which each Player Tank can inherit
    Public MustInherit Class Tank
        Inherits GameObject
        'Add hit points and attack points to the game object
        Public Property HP As Integer
        Public Property AP As Integer
        'Set the reload time (or cooldown) for each shot and the range a fired shot can travel
        Public Property ReloadTime As Single = 2.0!
        Public Property Range As Single = 280.0!
        'Specify the tank's turning rate in degrees-per-second
        Public Property TurnRate As Single = 7.5!
        'Holds the input key map for the player
        Public Property ForwardKey As Keys
        Public Property BackKey As Keys
        Public Property TurnLeftKey As Keys
        Public Property TurnRightKey As Keys
        Public Property FireKey As Keys
    
        'private variable for current cool down value
        Private coolDown As Single
    
        'gets the location of the end of the tank barrel 
        Public Function GetBarrelPosition() As PointF
            Return MathF.GetPositionToward(Position, FacingAngle, 48)
        End Function
    
        'sets common tank properties
        Public Overrides Sub OnInitialize(e As GameEngine)
            MyBase.OnInitialize(e)
            Sprite = New Sprite
            Sprite.SpriteSheet = e.SpriteSheets("TankGameSpriteSheet")
            Collider = New CircleCollider(Me)
            Collider.Origin = New PointF(-24, 0)
            Collider.Radius = 20.0!
            Speed = 24
            HP = 100
            AP = 10
        End Sub
    
        'process behaviors for a tank
        Public Overrides Sub OnUpdate(e As GameEngine)
            MyBase.OnUpdate(e)
            'if the HP is zero or less, destroy the tank
            If HP <= 0 Then
                e.RemoveObject(Me)
                Dim explosion As New Explosion
                explosion.Position = Position
                e.AddObject(explosion)
                Exit Sub
            End If
            'if there is a cool down running, reduce it
            If coolDown > 0 Then coolDown -= e.Time.LastFrame
            'process left/right input to adjust the facing angle
            If e.Input.IsDown(TurnLeftKey) Then
                FacingAngle = MathF.WrapDegrees(FacingAngle - TurnRate * e.Time.LastFrame)
            End If
            If e.Input.IsDown(TurnRightKey) Then
                FacingAngle = MathF.WrapDegrees(FacingAngle + TurnRate * e.Time.LastFrame)
            End If
            'process forward/back movement to update the position
            If e.Input.IsDown(ForwardKey) Then
                Position = MathF.GetPositionToward(Position, FacingAngle, Speed * e.Time.LastFrame)
            End If
            If e.Input.IsDown(BackKey) Then
                Position = MathF.GetPositionToward(Position, MathF.WrapDegrees(FacingAngle + MathF.HALF_CIRCLE), Speed * e.Time.LastFrame)
            End If
            'process the fire key by creating a new bullet
            If e.Input.WasPressed(FireKey) AndAlso coolDown <= 0 Then
                Dim bullet As New Bullet
                bullet.Position = GetBarrelPosition()
                bullet.FacingAngle = FacingAngle
                bullet.MaxDistance = Range
                bullet.AttackPower = AP
                e.AddObject(bullet)
                coolDown = ReloadTime
            End If
        End Sub
    End Class
    
    'configure a tank with player 1 image and keymap
    Public Class Player1Tank
        Inherits Tank
        Public Overrides Sub OnInitialize(e As GameEngine)
            MyBase.OnInitialize(e)
            Sprite.Bounds = New RectangleF(0, 0, 44, 96)
            ForwardKey = Keys.W
            BackKey = Keys.S
            TurnLeftKey = Keys.A
            TurnRightKey = Keys.D
            FireKey = Keys.E
        End Sub
    End Class
    
    'configure a tank with player 2 image and keymap
    Public Class Player2Tank
        Inherits Tank
        Public Overrides Sub OnInitialize(e As GameEngine)
            MyBase.OnInitialize(e)
            Sprite.Bounds = New RectangleF(52, 0, 43, 96)
            ForwardKey = Keys.I
            BackKey = Keys.K
            TurnLeftKey = Keys.J
            TurnRightKey = Keys.L
            FireKey = Keys.U
        End Sub
    End Class
    
    'create a bullet which moves along a given trajectory for a given distance
    Public Class Bullet
        Inherits GameObject
    
        'hold the attack power of the tank which created the bullet
        Public AttackPower As Integer
        'hold the range that the tank can fire
        Public MaxDistance As Single
        'private variable to track distance traveled
        Private remainingDistance As Single
    
        Public Overrides Sub OnInitialize(e As GameEngine)
            MyBase.OnInitialize(e)
            Sprite = New Sprite
            Sprite.SpriteSheet = e.SpriteSheets("TankGameSpriteSheet")
            Sprite.Bounds = New RectangleF(288, 0, 8, 16)
            Collider = New CircleCollider(Me)
            Collider.Origin = New PointF(-4, 0)
            Collider.Radius = 4.0!
            Speed = 96
            ZOrder = 2
            remainingDistance = MaxDistance
        End Sub
    
        'handle collision with a tank
        Public Overrides Function OnCollision(e As GameEngine, other As GameObject) As Boolean
            'when a tank is hit
            If TypeOf other Is Tank Then
                'reduce the tank HP
                CType(other, Tank).HP -= AttackPower
                'remove the bullet from the game 
                e.RemoveObject(Me)
                'create a small explosion at the collision point
                Dim hit As New Explosion
                hit.Position = Position
                hit.Scale = 0.1
                e.AddObject(hit)
                'return true because this object was destroyed by the collision
                Return True
            End If
            Return MyBase.OnCollision(e, other)
        End Function
    
        'move the bullet along its trajectory until the max distance has expired
        Public Overrides Sub OnUpdate(e As GameEngine)
            MyBase.OnUpdate(e)
            Dim newPosition = MathF.GetPositionToward(Position, FacingAngle, Speed * e.Time.LastFrame)
            remainingDistance -= MathF.Distance(Position, newPosition)
            If remainingDistance > 0 Then
                Position = newPosition
            Else
                e.RemoveObject(Me)
            End If
        End Sub
    End Class
    
    'create an animated explosion effect
    Public Class Explosion
        Inherits GameObject
    
        'provide a scale factor for the animation image (its easy to scale an object with no collider)
        Public Property Scale As Single = 1.0!
    
        'keep track of the frames of animation and playback rate
        Private frameTime As Single = 1.0! / 33.0!
        Private frameCount As Integer = 14
    
        'initialize the explosion to the first frame
        Public Overrides Sub OnInitialize(e As GameEngine)
            MyBase.OnInitialize(e)
            Sprite = New Sprite
            Sprite.SpriteSheet = e.SpriteSheets("explosion")
            Sprite.Bounds = New RectangleF(0, 0, 110, 110)
            ZOrder = 3
        End Sub
    
        'perform a custom render so that the image can be scaled
        Public Overrides Sub OnRender(e As GameEngine, gfx As Graphics)
            gfx.TranslateTransform(Position.X, Position.Y)
            gfx.ScaleTransform(Scale, Scale) 'add a scale operation to normal drawing
            gfx.RotateTransform(MathF.WrapDegrees(FacingAngle + MathF.RIGHT_ANGLE))
            gfx.TranslateTransform(-Position.X, -Position.Y)
            Dim dstBounds = New RectangleF(Position.X - Sprite.Bounds.Width / 2.0!, Position.Y - Sprite.Bounds.Height / 2.0!, Sprite.Bounds.Width, Sprite.Bounds.Height)
            gfx.DrawImage(Sprite.SpriteSheet, dstBounds, Sprite.Bounds, GraphicsUnit.Pixel)
            gfx.ResetTransform()
        End Sub
    
        'update the frames of the animation until it finishes, then destroy the object
        Public Overrides Sub OnUpdate(e As GameEngine)
            MyBase.OnUpdate(e)
            frameTime -= e.Time.LastFrame
            If frameTime <= 0 Then
                frameCount -= 1
                If frameCount = 0 Then
                    e.RemoveObject(Me)
                Else
                    Sprite.Bounds = New RectangleF(Sprite.Bounds.X + Sprite.Bounds.Width, Sprite.Bounds.Y, Sprite.Bounds.Width, Sprite.Bounds.Height)
                End If
            End If
        End Sub
    End Class
    #End Region
    
    #Region " Game Engine Objects "
    'define the main game engine
    Public Class GameEngine
        'track the keyboard input
        Public ReadOnly Property Input As New GameInput
        'track the game execution time
        Public ReadOnly Property Time As New GameClock
        'hold an instance of the current game map
        Public Property GameMap As GameMap
        'hold a dictionary of spritsheets keyed by file name
        Public ReadOnly Property SpriteSheets As New Dictionary(Of String, Image)
        'indicate if the engine is running
        Public ReadOnly Property IsRunning As Boolean
        'hold the client size of the render window
        Public ReadOnly Property WindowSize As SizeF
    
        'create a private graphics buffer for rendering
        Private graphicsBuffer As BufferedGraphics
        'create a private list of active game object instances
        Private gameObjects As New List(Of GameObject)
        'create a queue to hold new game objects which need to be initialized and added to the game
        Private newObjectQueue As New Queue(Of GameObject)
    
        'create the game engine instance with a reference to the control where the game will be rendered
        Public Sub New(canvasControl As Control)
            graphicsBuffer = BufferedGraphicsManager.Current.Allocate(canvasControl.CreateGraphics, canvasControl.ClientRectangle)
            WindowSize = canvasControl.ClientSize
        End Sub
    
        'provide a method for adding new game objects to the engine
        Public Sub AddObject(obj As GameObject)
            newObjectQueue.Enqueue(obj)
        End Sub
    
        'load all sprite sheets from the .png files in the local Assets folder
        Public Sub LoadAssets()
            For Each imageFile In IO.Directory.GetFiles(IO.Path.Combine(My.Application.Info.DirectoryPath, "Assets"), "*.png")
                SpriteSheets(IO.Path.GetFileNameWithoutExtension(imageFile)) = Bitmap.FromFile(imageFile)
            Next
        End Sub
    
        'provide a method for removing a game object from the engine
        Public Sub RemoveObject(obj As GameObject)
            gameObjects.Remove(obj)
        End Sub
    
        'execute the main game loop to run the game
        Public Async Function Run() As Task
            If Not _IsRunning Then
                _IsRunning = True
                'enter the main game loop
                Do While _IsRunning
                    'update the game execution time
                    Time.Update()
                    'initialize new game objects and add them to the game
                    While newObjectQueue.Count > 0
                        Dim obj = newObjectQueue.Dequeue
                        If Not obj.IsInitialized Then obj.OnInitialize(Me)
                        gameObjects.Add(obj)
                    End While
                    'check collision of game objects
                    For i = gameObjects.Count - 1 To 1 Step -1
                        Dim obj1 = gameObjects(i)
                        If obj1.Collider IsNot Nothing Then
                            For j = i - 1 To 0 Step -1
                                Dim obj2 = gameObjects(j)
                                If obj2.Collider IsNot Nothing Then
                                    If obj1.Collider.CollidesWith(obj2.Collider) Then
                                        obj2.OnCollision(Me, obj1)
                                        If obj1.OnCollision(Me, obj2) Then Exit For
                                    End If
                                End If
                            Next
                        End If
                    Next
                    'update all game objects
                    For i = gameObjects.Count - 1 To 0 Step -1
                        gameObjects(i).OnUpdate(Me)
                    Next
                    'render the game
                    graphicsBuffer.Graphics.Clear(Color.Black)
                    If GameMap IsNot Nothing Then GameMap.OnRender(Me, graphicsBuffer.Graphics)
                    Dim zorderObjects = (From obj In gameObjects Where obj.Sprite IsNot Nothing Order By obj.ZOrder Descending)
                    For i = zorderObjects.Count - 1 To 0 Step -1
                        zorderObjects(i).OnRender(Me, graphicsBuffer.Graphics)
                    Next
                    graphicsBuffer.Render()
                    'update keyboard input
                    Input.Update()
                    'execute an async delay to make the game loop run asynchronously which keeps the form active
                    Await Task.Delay(1)
                Loop
            End If
        End Function
    
        'provide a method to stop the game
        Public Sub [Stop]()
            _IsRunning = False
        End Sub
    End Class
    
    'define a simple tiled-background map object
    Public Class GameMap
        Public Property TileSprite As Sprite
    
        Public Overridable Sub OnRender(e As GameEngine, gfx As Graphics)
            For y = 0 To e.WindowSize.Height - 1 Step TileSprite.Bounds.Height
                For x = 0 To e.WindowSize.Width - 1 Step TileSprite.Bounds.Width
                    Dim dstBounds As New RectangleF(x, y, TileSprite.Bounds.Width, TileSprite.Bounds.Height)
                    gfx.DrawImage(TileSprite.SpriteSheet, dstBounds, TileSprite.Bounds, GraphicsUnit.Pixel)
                Next
            Next
        End Sub
    End Class
    
    'define the base game object from which all game actors and elements are made
    Public Class GameObject
        'objects with collision will be assigned a collider
        Public Property Collider As CircleCollider
        'all objects have a position
        Public Property Position As PointF
        'all objects face an angle in degrees
        Public Property FacingAngle As Single
        'moving objects have a speed they move at
        Public Property Speed As Single
        'visible objects will be assigned a sprite
        Public Property Sprite As Sprite
        'drawn items are sorted by z-order, descending
        Public Property ZOrder As Integer
        'used by the engine to ensure an object instance is initialized exactly one time
        Public ReadOnly Property IsInitialized As Boolean
    
        Public Overridable Sub OnInitialize(e As GameEngine)
            'override to provide the initial configuration of a game object instance
            _IsInitialized = True
        End Sub
    
        Public Overridable Function OnCollision(e As GameEngine, other As GameObject) As Boolean
            'override to handle collison events
            'indicate whether or not the object was destroyed by the collision and removed from the game engine
            Return False
        End Function
    
        Public Overridable Sub OnRender(e As GameEngine, gfx As Graphics)
            'default drawing for rotated, non-scaling sprites
            gfx.TranslateTransform(Position.X, Position.Y)
            gfx.RotateTransform(MathF.WrapDegrees(FacingAngle + MathF.RIGHT_ANGLE))
            gfx.TranslateTransform(-Position.X, -Position.Y)
            Dim dstBounds = New RectangleF(Position.X - Sprite.Bounds.Width / 2.0!, Position.Y - Sprite.Bounds.Height / 2.0!, Sprite.Bounds.Width, Sprite.Bounds.Height)
            gfx.DrawImage(Sprite.SpriteSheet, dstBounds, Sprite.Bounds, GraphicsUnit.Pixel)
            gfx.ResetTransform()
        End Sub
    
        Public Overridable Sub OnUpdate(e As GameEngine)
            'override in derived classes to add behavior code
        End Sub
    End Class
    
    'define a sprite as an image and a bounding rectangle within the image
    Public Class Sprite
        Public Property SpriteSheet As Image
        Public Property Bounds As RectangleF
    End Class
    
    'Circular collider for effecient collision detection
    Public Class CircleCollider
        'owning game object
        Public ReadOnly GameObject As GameObject
        'offset from center of game object
        Public Origin As PointF
        'radius of circle from origin
        Public Radius As Single
    
        Public Sub New(obj As GameObject)
            GameObject = obj
        End Sub
    
        Public Function CollidesWith(other As CircleCollider) As Boolean
            'collider position must be offset by owner position and rotation
            Dim m As New Drawing2D.Matrix
            m.Translate(GameObject.Position.X, GameObject.Position.Y)
            m.Rotate(GameObject.FacingAngle)
            Dim o1 = {Origin}
            m.TransformPoints(o1)
            'repeat process for other collider
            m.Reset()
            m.Translate(other.GameObject.Position.X, other.GameObject.Position.Y)
            m.Rotate(other.GameObject.FacingAngle)
            Dim o2 = {other.Origin}
            m.TransformPoints(o2)
            'compare collider distances
            Return MathF.Distance(o1(0), o2(0)) <= Radius + other.Radius
        End Function
    End Class
    
    'Synchronized game keyboard input state
    Public Class GameInput
        'hold the keyboard state from the previous frame
        Private lastKeyState As New Dictionary(Of Keys, Boolean)
        'hold the keyboard state for the current frame
        Private currentKeyState As New Dictionary(Of Keys, Boolean)
    
        Public Function IsDown(key As Keys) As Boolean
            If Not currentKeyState.ContainsKey(key) Then Return False
            Return currentKeyState(key)
        End Function
    
        Public Sub SetKeyState(key As Keys, pressed As Boolean)
            currentKeyState(key) = pressed
        End Sub
    
        Public Function WasPressed(key As Keys) As Boolean
            If Not currentKeyState.ContainsKey(key) Then Return False
            Return currentKeyState(key) = False AndAlso lastKeyState(key) = True
        End Function
    
        Public Sub Update()
            For Each k As Keys In currentKeyState.Keys
                lastKeyState(k) = currentKeyState(k)
            Next
        End Sub
    End Class
    
    'Game execution timing mechanism 
    Public Class GameClock
        Public ReadOnly Property LastFrame As Single
        Public ReadOnly Property Elapsed As Single
    
        Private timer As New Stopwatch
    
        Public Sub Update()
            timer.Stop()
            _LastFrame = CSng(timer.Elapsed.TotalSeconds)
            _Elapsed += _LastFrame
            timer.Restart()
        End Sub
    End Class
    #End Region
    
    #Region " Math Helper "
    'Static Math Helper Functions
    Public NotInheritable Class MathF
        Public Const HALF_CIRCLE As Single = 180.0!
        Public Const RIGHT_ANGLE As Single = 90.0!
        Public Const PI As Single = 3.14159274!
        Public Const TWO_PI As Single = PI * 2.0!
    
        Public Shared Function Cos(ByVal radians As Single) As Single
            Return CSng(Math.Cos(CDbl(radians)))
        End Function
    
        Public Shared Function DegreesToRadians(ByVal degrees As Single) As Single
            Return degrees * (PI / HALF_CIRCLE)
        End Function
    
        Public Shared Function Distance(a As PointF, b As PointF) As Single
            Return MathF.Sqrt(MathF.Square(b.X - a.X) + MathF.Square(b.Y - a.Y))
        End Function
    
        Public Shared Function GetPositionToward(ByVal source As PointF, ByVal angle As Single, ByVal distance As Single) As PointF
            angle = DegreesToRadians(angle)
            Return source + New SizeF(MathF.Cos(angle) * distance, MathF.Sin(angle) * distance)
        End Function
    
        Public Shared Function RadiansToDegrees(ByVal radians As Single) As Single
            Return radians * (HALF_CIRCLE / PI)
        End Function
    
        Public Shared Function Sin(ByVal radians As Single) As Single
            Return CSng(Math.Sin(CDbl(radians)))
        End Function
    
        Public Shared Function Sqrt(ByVal value As Single) As Single
            Return CSng(CDbl(value) ^ 0.5)
        End Function
    
        Public Shared Function Square(ByVal value As Single) As Single
            Return value * value
        End Function
    
        Public Shared Function WrapDegrees(degrees As Single) As Single
            Return RadiansToDegrees(WrapRadians(DegreesToRadians(degrees)))
        End Function
    
        Public Shared Function WrapRadians(ByVal radians As Single) As Single
            While radians < -PI
                radians += TWO_PI
            End While
            While radians > PI
                radians -= TWO_PI
            End While
            Return radians
        End Function
    
        Protected Sub New()
        End Sub
    End Class
    #End Region
    

    I hope this demonstrates the basics of a game engine clearly enough that you can use it as a reference model for building your own game engine implementation.  There are a lot of possible variances of the approaches used in this example and there will likely be need for optimization, depending on how you expand upon the base example.  But at a high level, this represents the various steps and stages that your code should go through to execute a game smoothly in terms of both performance and logic behavior.

    Let me know if you have any questions about the "why" or "how" of anything in the code.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    • Marked as answer by Waliur Rahman Sunday, March 19, 2017 1:38 PM
    Saturday, March 18, 2017 8:30 PM
    Moderator
  • Hi Reed,

    The tank game looks impressive.

    I am trying to make the project but I seem to show a lot of errors. Are there some declarations missing?

    For example in LoadAssets sub it seems imagefile is undefined? Also lots of Option Strict things. I'm not sure I copied the images to the assets folder and set the copy always etc.. I had to add an imports but it seems something is missing from the posted code?

    Saturday, March 18, 2017 9:58 PM
  • Hi Reed,

    The tank game looks impressive.

    I am trying to make the project but I seem to show a lot of errors. Are there some declarations missing?

    For example in LoadAssets sub it seems imagefile is undefined? Also lots of Option Strict things. I'm not sure I copied the images to the assets folder and set the copy always etc.. I had to add an imports but it seems something is missing from the posted code?

    Its VS2015, Framework 4.6 so maybe that's the problem for you?  There's nothing missing...

    The code has Option Strict On, but I do use type inference (which is what's going on in LoadAssets).  I'm not sure why that's not being allowed in your project.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Saturday, March 18, 2017 11:28 PM
    Moderator
  • Woaaah that code looks awesome Im gonna first do as you said implement it and play around with it so I can understand some stuff. Before I do anything else furthermore. 

    WRA

    Sunday, March 19, 2017 1:00 PM
  • Hi Reed,

    The tank game looks impressive.

    I am trying to make the project but I seem to show a lot of errors. Are there some declarations missing?

    For example in LoadAssets sub it seems imagefile is undefined? Also lots of Option Strict things. I'm not sure I copied the images to the assets folder and set the copy always etc.. I had to add an imports but it seems something is missing from the posted code?

    Its VS2015, Framework 4.6 so maybe that's the problem for you?  There's nothing missing...

    The code has Option Strict On, but I do use type inference (which is what's going on in LoadAssets).  I'm not sure why that's not being allowed in your project.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Ok. Well sorry, I guess I had turned off the default Option Infer option while trying to get tit to run.  I did not really know what it was. Also needed imports threading for async. I added these two lines after Option Strict in the code and then it goes in my project:

        Option Infer On

        Imports System.Threading.Tasks

    I ran the tank using keyboard WASD and E to fire and saw the gif explosion on the other object.

    Looks pretty cool. Not sure how the rest may work yet if there is more operational.

    I like how the tank runs. And the gif explosion. I would make the tank faster and the explosion bigger. :)

    Sunday, March 19, 2017 1:20 PM
  • Hi reed thanks for the project I found it useful especially the designs made. 

    I got some questions: How did you make the tanks blend in with the grass is the first? I need to do that for my game. 

    2) Where do you get these awesome art? I need to make some backgrounds for the battle field: one for grass, snow and sand. 

    3) Is there a way I could make a map design such as build a bridge and the tanks can't cross the water?


    WRA

    Sunday, March 19, 2017 1:23 PM
  • @Reed 

    believe me when I say I found quite useful stuff outta this project such as I need to set a range of what tanks can attack from which is something I found. 

    I could use some things in here to help with my project. 


    WRA

    Sunday, March 19, 2017 1:24 PM
  • PS Reed,

    Is there a standard size these grids are made? ie 50x50 pixels.

    In the code do the engines normaly operate on the grid rows and cols coordinates? I mean you mention (and one can see as the tank runs and rotates) you use pixels for the coordinates and calcs. In the example Wali posted the pixel locations are converted to cols and rows and those grid coords used for movement and collisions, drawing, etc.

    You know I am not a gamer so I dont know how the games normally work or if some work one way some another.

    Thanks for posting the example!

    Sunday, March 19, 2017 1:33 PM
  • The game freezes when both tanks are in range or when the two tanks attack each other. 

    I didn't change any of the code though.


    WRA

    Sunday, March 19, 2017 1:35 PM
  • Im not gamer programmer either dont worry.

    I just felt inspiration to make a game for my coursework. 

    I have learnt so much from it and develop since I actually started computer science.


    WRA

    Sunday, March 19, 2017 1:36 PM
  • @Tommy,

    Glad you got it sorted out.

    Option Infer enables type inference which allows a variable type to be determined by the right-hand operator.  So "Dim x = 1" would make x and Integer, and "Dim x = "Hello"" would make x a String.  The variable x is still strongly typed, the type was just inferred by the assignment.

    System.Threading.Tasks is a default import for all projects in my environment - not sure why you had to add it separately.

    The tanks can be customized in the Player1Tank and Player2Tank classes (or the base Tank class).  You can adjust the speed, turning rate, rate of fire, etc. for each tank.  You could also change the Scale property of the explosion sprite for either the bullet impact or the tank destruction to make it bigger.

    There's nothing more implemented than driving the two tanks and shooting at each other, but I did include a building image in the sprite sheet so it would be relatively easy to add a static building that both tanks could shoot at.

    Note that the explosion is not a GIF - its just an animation over a sprite strip.

    As for the grid question, that is entirely up to the kind of game.  There is no set "rule" as to how your game objects move.  One common deciding factor is whether the action of the game is real-time or turn-based.  A turn-based game is more likely to utilize (and benefit from) a game map split into a tiled grid.  A real-time game is more likely to move by real pixel locations to keep the action feeling smooth.

    Does that make sense?


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Sunday, March 19, 2017 1:52 PM
    Moderator
  • @Waliur,

    I'm glad this example has been of some use to you.

    By "blend with the grass", are you referring to the way the tank appears to be "cut out"?  That is, the tank is not a perfect rectangle with white space around it.  Is that what you mean?  If so, that is just a matter of using transparent images for your sprite sheet.  Notice I used a PNG file, not a BMP file.

    The artwork all came from a graphic resource package I purchased - it wasn't cheap either.  I would suggest that you make your own place-holder graphics in Paint - just colored shapes, nothing pretty.  That's enough to mock up a game and then you can have an artist do real graphics for you.  There's three ways to get artwork:  draw it yourself if you are able (I am not), get a friend or relative to do it for you, or buy stock artwork/hire an artist.

    Finally, yes, you could certainly make a map that way, and there are a number of ways to do it.  With this engine, you'd probably need to expand the Collider object so that there were different shaped colliders (not too difficult to change in the code).  Then you could make a long rectangle of water, give it a rectangular collider, and add collision code to the tanks to prevent them from driving over the water.  Then you could add the bridge object, overlapping the water object, so that the tanks hit the bridge collider and are allowed to pass over it.

    You can do almost anything you can think of.  The trick is thinking of everything you want to do ahead of time so that you can design the engine accordingly.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Sunday, March 19, 2017 2:05 PM
    Moderator
  • Reed,

    "System.Threading.Tasks is a default import for all projects in my environment "

    It is not referenced in my default project vs 2015 community. I dont think I have changed that but not sure.

    And my default project is Option Infer Off. I am not sure if I changed that.


    "Does that make sense?"

    Yes.

    Sunday, March 19, 2017 2:12 PM
  • @Reed 

    Afternoon, the game seems to freeze when the tanks are either in range or attack each other. 

    Could the reason be to do with the performance of the computer or the code.

    I can't figure out which one it is. 


    WRA

    Monday, March 20, 2017 1:47 PM
  • @Reed 

    Afternoon, the game seems to freeze when the tanks are either in range or attack each other. 

    Could the reason be to do with the performance of the computer or the code.

    I can't figure out which one it is. 


    WRA

    Wali,

    Reed will be around one of these days.

    In the mean time, here is another example with some ideas similar to Reed's but more at my level. This one uses all pixel based coordinates and draws vector graphics.

    There is run mode and drawing mode. In run mode you can drive the tank, rotate, and fire using the popup toolbar. In draw mode you can move and rotate the tanks with the mouse. Note the sprite info popup that shows the sprite data like name and angle.

    Also note in draw mode the app is only responding to mouse events from the user. In run mode there is a timer running the game loop animation continuously. The user controls action with mouse events and each timer tick event the game board is updated and redrawn based on the user actions.

    The idea is you can draw the map board (if added features) and then run the game interactively like VS IDE. Need to add much more to it like save the map etc.

    Use the LMB to drag the map. Click a Sprite to give it focus then drag (draw mode) or click toolbar (run mode).

    Finally this example is not using "tiles" to draw. The grid tiles are drawn but not used. Although this can be added if the game will use it. All locations and movement are based on the pixel screen coordinates.

    I wanted to show how easy it is to draw all the graphics. All the screen graphics and controls are drawn, not vb controls. You can draw on the map to show any info you want without messy controls.

    This is a complete one form example. The controls are made in the code. Just make an empty form and paste the code with the classes.

    Option Strict On
    Imports System.Drawing.Drawing2D
    
    Public Class Form2
        Private WithEvents Timer1 As New Timer With {.Interval = 50, .Enabled = False}
        Private WithEvents RunCbx As New CheckBox With {.Parent = Me, .Location = New Point(50, 0), .Text = "Run", .ForeColor = Color.AntiqueWhite}
        Private WithEvents TankNewBtn As New Button With {.Parent = Me, .Location = New Point(RunCbx.Right + 30, 0), .Text = "New Tank", .ForeColor = Color.AntiqueWhite}
        Private WithEvents MapPic As New PictureBox With {.Parent = Me}
        Private GridSize As New Size(50, 50)
        Private OriginPt As New Point(100, 100)
        Private ScaleFactor As Single = 1
        Private Sprites As New List(Of Sprite)
        Private SelectedSprite As Integer = -1
        Private MouseDownOriginPt, MouseDownPt, MouseMovingPt, MouseDownOffset As Point
        Private MouseDragStatus As Integer
        Private ToolBarTank As New ToolBar
        Private Missle1 As New Missle
    
        Private Sub Form3_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            DoubleBuffered = True
            BackColor = Color.Black
            Text = "Mine Field"
            Size = New Size(500, 400)
    
            'make the sprites and setup
            For i As Integer = 1 To 2
                Dim thisSprite As Sprite = GetNewTank(New Point(i * GridSize.Width * 2, 0))
                Sprites.Add(thisSprite)
            Next
            Sprites(1).Angle = 180
    
            Form3_Resize(0, Nothing)
            RunCbx.Checked = True
        End Sub
    
        Private Sub Form3_Resize(sender As Object, e As EventArgs) Handles Me.Resize
            Dim borderright As Integer = 0
            Dim bordertop As Integer = 30
            MapPic.Location = New Point(0, bordertop)
            MapPic.Size = New Size(ClientSize.Width - borderright, ClientSize.Height - bordertop)
            MapPic.Invalidate()
        End Sub
    
        'Private Sub Form5_MouseWheel(sender As Object, e As MouseEventArgs) Handles Me.MouseWheel
        '    ScaleFactor += CSng(e.Delta / 1000)
        '    MapPic.Invalidate()
        'End Sub
    
        Private Sub MapPic_Paint(sender As Object, e As PaintEventArgs) Handles MapPic.Paint
            With e.Graphics
                'background
                .FillRectangle(New SolidBrush(Color.FromArgb(100, Color.Khaki)), MapPic.ClientRectangle)
                .TranslateTransform(OriginPt.X, OriginPt.Y)
                .ScaleTransform(ScaleFactor, ScaleFactor)
    
                DrawGrid(e.Graphics)
    
                'draw the sprites
                For i As Integer = 0 To Sprites.Count - 1
                    If i = SelectedSprite AndAlso MouseDragStatus > 0 And MouseDragStatus < 3 Then
                        'this sprite is being dragged
                        Sprites(i).DrawSprite(e.Graphics, MouseMovingPt)
                    Else
                        'draw normal sprite
                        Sprites(i).DrawSprite(e.Graphics, Sprites(i).Location)
                    End If
                Next
    
                'origin point
                Dim t As String
                Dim rect As New Rectangle(CInt(-GridSize.Width / 2), CInt(-GridSize.Height / 2), GridSize.Width, GridSize.Height)
                Dim r As Integer = CInt(GridSize.Width / 4)
                rect = New Rectangle(-r, -r, 2 * r, 2 * r)
                .DrawEllipse(New Pen(Color.Gray, 1), rect)
    
                'mouse moving highlights
                If SelectedSprite > -1 Then
                    rect = Sprites(SelectedSprite).GetSpriteRectFromPoint(Sprites(SelectedSprite).Location)
                    Select Case MouseDragStatus
                        Case 0   'hightlight the selected object
                            .FillEllipse(New SolidBrush(Color.FromArgb(70, Color.OrangeRed)), rect)
                            .DrawEllipse(New Pen(Color.Firebrick, 1), rect)
                        Case 4 'angle
                            Using p As New Pen(Color.AliceBlue, 2)
                                p.DashStyle = Drawing2D.DashStyle.Dash
                                .DrawLine(p, Sprites(SelectedSprite).Location, MouseMovingPt)
                            End Using
                    End Select
    
                    If RunCbx.Checked Then
                        'running
                        Select Case MouseDragStatus
                            Case 12, 13
                                Using p As New Pen(Color.Red, 2)
                                    p.DashStyle = Drawing2D.DashStyle.Dash
                                    Dim dx As Double = 3 * GridSize.Width * Math.Cos(Sprites(SelectedSprite).Angle / 57.3)
                                    Dim dy As Double = 3 * GridSize.Width * Math.Sin(Sprites(SelectedSprite).Angle / 57.3)
    
                                    Dim pt As New Point(CInt(Sprites(SelectedSprite).Location.X + dx),
                                                            CInt(Sprites(SelectedSprite).Location.Y + dy))
                                    .DrawLine(p, Sprites(SelectedSprite).Location, pt)
                                End Using
                        End Select
                    Else
                        'drawing
                        Select Case MouseDragStatus
                            Case 0, 4
                                t = Sprites(SelectedSprite).Name & vbLf &
                                              Sprites(SelectedSprite).Angle.ToString("f1") & " Deg."
                                .DrawString(t, New Font("arial", 12), Brushes.Yellow, rect.X + GridSize.Width, rect.Y + GridSize.Height)
                        End Select
                    End If
                End If
    
                If ToolBarTank.Visible Then ToolBarTank.Draw(e.Graphics)
                If Missle1.MissleStep > -1 Then
                    .FillEllipse(Brushes.OrangeRed, New RectangleF(Missle1.Location.X, Missle1.Location.Y, 5, 5))
    
                End If
                If Missle1.ExplosionStep > -1 Then
                    Dim x As Double = Sprites(Missle1.MissleSpriteTarget).Location.X - (Missle1.ExplosionStep / 2)
                    Dim y As Double = Sprites(Missle1.MissleSpriteTarget).Location.Y - (Missle1.ExplosionStep / 2)
    
                    .FillEllipse(Brushes.OrangeRed, New RectangleF(CSng(x), CSng(y), Missle1.ExplosionStep, Missle1.ExplosionStep))
                End If
                'draw time & header
                .ResetTransform()
                If RunCbx.Checked Then t = "Running  " & Now.ToLongTimeString & "  " Else t = "Drawing  "
                .DrawString(t, New Font("arial", 12), Brushes.White, 20, 0)
                If Not Missle1.MissleMsg = "" Then .DrawString(Missle1.MissleMsg, New Font("arial", 12), Brushes.Yellow, 20, 20)
    
            End With
        End Sub
    
        Private Sub MapPic_MouseDown(sender As Object, e As MouseEventArgs) Handles MapPic.MouseDown
            Dim eTranslated As Point = GetGridPointFromClientPt(e.Location)
            Dim rect As Rectangle
            MouseDownPt = e.Location
            MouseDragStatus = 0
            MouseDownOriginPt = OriginPt
            Missle1.MissleStep = -1
            Missle1.MissleMsg = ""
    
            'process toolbar if shown
            If ToolBarTank.Visible Then
                If ToolBarTank.Rect.Contains(eTranslated) Then
                    'clicked on toolbar
                    Select Case eTranslated.X - ToolBarTank.Rect.X
                        Case < CInt(ToolBarTank.ButtonWidth)
                            'move left 'forward
                            If e.Button = MouseButtons.Left Then
                                MouseDragStatus = 10
                                Cursor = Cursors.PanNorth
                            Else
                                'back
                                MouseDragStatus = 11
                                Cursor = Cursors.PanSouth
                            End If
                        Case < CInt(2 * ToolBarTank.ButtonWidth)
                            'rotate, left 'counterclockwise
                            If e.Button = MouseButtons.Left Then
                                MouseDragStatus = 13
                                Cursor = Cursors.PanWest
                            Else
                                MouseDragStatus = 12
                                Cursor = Cursors.PanEast
                            End If
                        Case Else
                            'fire
                            Missle1.MissleStep = 1
                            Missle1.MissleMsg = "Missle Tracking..."
                            ToolBarTank.Visible = False
                    End Select
                    Exit Sub
                Else
                    ToolBarTank.Visible = False
                End If
            End If
    
            'if object selected then move it
            SelectedSprite = -1
            For i As Integer = 0 To Sprites.Count - 1
                rect = Sprites(i).GetSpriteRectFromPoint(Sprites(i).Location)
                If rect.Contains(eTranslated) Then
                    MouseDownOffset = New Point(eTranslated.X - rect.X, eTranslated.Y - rect.Y)
                    SelectedSprite = i
                    If RunCbx.Checked Then ToolBarShow(ToolBarTank, New Point(rect.Right, rect.Bottom))
                    Exit For
                End If
            Next
    
            If RunCbx.Checked Then
                'running
                If SelectedSprite = -1 Then
                    'move screen
                    MouseDragStatus = 3
                    Cursor = Cursors.Hand
                End If
            Else
                'drawing mode
                If e.Button = MouseButtons.Left Then
                    If SelectedSprite > -1 Then
                        'move object
                        MouseDragStatus = 1
                    Else
                        'move screen
                        MouseDragStatus = 3
                        Cursor = Cursors.Hand
                    End If
                Else 'rmb click 
                    'change angle
                    If SelectedSprite > -1 Then MouseDragStatus = 4
                End If
            End If
        End Sub
    
        Private Sub MapPic_MouseMove(sender As Object, e As MouseEventArgs) Handles MapPic.MouseMove
            If MouseDragStatus > 0 Then
                MouseMovingPt = GetGridPointFromClientPt(e.Location)
    
                Select Case MouseDragStatus
                    Case 1, 2 'drag sprite
                        MouseDragStatus = 2
                    Case 3 'drag map
                        OriginPt.X = MouseDownOriginPt.X + (e.X - MouseDownPt.X)
                        OriginPt.Y = MouseDownOriginPt.Y + (e.Y - MouseDownPt.Y)
                    Case 4 'sprite angle
                        Sprites(SelectedSprite).Angle = 180 + CSng(57.8 * Math.Atan2((MouseDownPt.Y - e.Y), (MouseDownPt.X - e.X)))
                        If Sprites(SelectedSprite).Angle > 360 Then Sprites(SelectedSprite).Angle -= 360
                        If Sprites(SelectedSprite).Angle < 0 Then Sprites(SelectedSprite).Angle += 360
                End Select
                MapPic.Invalidate()
            End If
        End Sub
    
        Private Sub MapPic_MouseUp(sender As Object, e As MouseEventArgs) Handles MapPic.MouseUp
            If MouseDragStatus > 0 Then
                Select Case MouseDragStatus
                    Case 2 'save new location
                        Sprites(SelectedSprite).Location = MouseMovingPt
                End Select
            End If
            MouseDragStatus = 0
            Cursor = Cursors.Default
            MapPic.Invalidate()
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            If Missle1.ExplosionStep > -1 Then
                Missle1.ExplosionStep += 5
                If Missle1.ExplosionStep > GridSize.Width Then
                    Missle1.ExplosionStep = -1
                    Missle1.MissleMsg = Sprites(Missle1.MissleSpriteTarget).Name &
                            " - Destroyed by: " & Sprites(SelectedSprite).Name
    
                    Sprites.Remove(Sprites(Missle1.MissleSpriteTarget))
                    SelectedSprite = -1
                    ToolBarTank.Visible = False
                End If
            End If
    
            If Missle1.MissleStep > 0 Then
                'moving missle
                With Missle1
                    .MissleStep += 10
                    If .MissleStep > 600 Then
                        .MissleStep = -1
                        .MissleMsg = "Lost Contact."
                    Else
                        'missle location
                        .Location = New Point(
                     CInt(Sprites(SelectedSprite).Location.X + (.MissleStep * Math.Cos(Sprites(SelectedSprite).Angle / 57.3))),
                     CInt(Sprites(SelectedSprite).Location.Y + (.MissleStep * Math.Sin(Sprites(SelectedSprite).Angle / 57.3))))
    
                        'see if missle in sprite rect
                        Dim rect1 As Rectangle
                        For i As Integer = 0 To Sprites.Count - 1
                            If Not i = SelectedSprite Then
                                rect1 = Sprites(i).GetSpriteRectFromPoint(Sprites(i).Location)
                                If rect1.Contains(.Location) Then
                                    .MissleStep = -1
                                    .MissleSpriteTarget = i
                                    .ExplosionStep = 1
                                    Exit For
                                End If
                            End If
                        Next
                    End If
                End With
            Else
    
                If MouseDragStatus > 0 AndAlso SelectedSprite > -1 Then
                    'moving tank
                    Dim dx, dy As Single
                    Dim r As Double = GridSize.Width / 10
                    dx = CSng(r * Math.Cos(Sprites(SelectedSprite).Angle / 57.8))
                    dy = CSng(r * Math.Sin(Sprites(SelectedSprite).Angle / 57.8))
                    Select Case MouseDragStatus
                        Case 10  'forward
                            Sprites(SelectedSprite).Location.X += dx
                            Sprites(SelectedSprite).Location.Y += dy
                        Case 11  'backward
                            Sprites(SelectedSprite).Location.X -= dx
                            Sprites(SelectedSprite).Location.Y -= dy
                        Case 12  'clockwise
                            Sprites(SelectedSprite).Angle += 2
                            If Sprites(SelectedSprite).Angle > 360 Then Sprites(SelectedSprite).Angle -= 360
                        Case 13  'counterclockwise
                            Sprites(SelectedSprite).Angle -= 2
                            If Sprites(SelectedSprite).Angle < 0 Then Sprites(SelectedSprite).Angle += 360
                    End Select
                End If
            End If
            MapPic.Invalidate()
        End Sub
    
        Private Sub TankNewBtn_Click(sender As Object, e As EventArgs) Handles TankNewBtn.Click
            Dim spt As Sprite = GetNewTank(New Point(CInt((MapPic.ClientSize.Width / 2) - OriginPt.X),
                                                          CInt((MapPic.ClientSize.Height / 2) - OriginPt.Y)))
            Sprites.Add(spt)
        End Sub
    
        Private Sub RunCbx_CheckedChanged(sender As Object, e As EventArgs) Handles RunCbx.CheckedChanged
            If RunCbx.Checked Then
                Timer1.Start()
            Else
                Timer1.Stop()
                MapPic.Refresh()
            End If
        End Sub
    
        Private Sub DrawGrid(g As Graphics)
            'round to even grid increment for origin offest
            Dim dx As Single = CInt(GridSize.Width * Math.Floor(-OriginPt.X / GridSize.Width))
            Dim dy As Single = CInt(GridSize.Height * Math.Floor(-OriginPt.Y / GridSize.Height))
            Dim w As Integer = CInt(GridSize.Width * (1 + Math.Ceiling(MapPic.ClientSize.Width / GridSize.Width)))
            Dim h As Integer = CInt(GridSize.Height * (1 + Math.Ceiling(MapPic.ClientSize.Height / GridSize.Height)))
    
            If GridSize.Width > 0 AndAlso GridSize.Height > 0 Then
                Using p1 As New Pen(Color.DimGray, 1)
                    For x As Single = dx To dx + w Step GridSize.Width
                        g.DrawLine(p1, x, dy, x, dy + h)
                    Next
                    For y As Single = dy To dy + h Step CInt(GridSize.Height)
                        g.DrawLine(p1, dx, y, dx + w, y)
                    Next
                End Using
            End If
        End Sub
    
        Private Sub ToolBarShow(tb As ToolBar, pt As Point)
            tb.Visible = True
    
            'check toolbar within picturebox window
            Dim w As Integer = tb.Buttons * tb.ButtonWidth
            Dim r As Integer = (MapPic.ClientSize.Width - w) - OriginPt.X
            If pt.X > r Then pt.X = r
            r = (MapPic.ClientSize.Height - tb.ButtonWidth) - OriginPt.Y
            If pt.Y > r Then pt.Y = r
    
            tb.Rect = New Rectangle(pt, New Size(w, tb.ButtonWidth))
    
        End Sub
    
        Private Function GetGridPointFromClientPt(thisPt As Point) As Point
            Return New Point(thisPt.X - OriginPt.X, thisPt.Y - OriginPt.Y)
        End Function
    
        Private Function GetNewTank(thisPnt As Point) As Sprite
            Static TankCount As Integer = 0
            Dim thisSprite As New Sprite
            TankCount += 1
            thisSprite.Style = 11  'vector tank
            thisSprite.Name = "Tank " & TankCount.ToString
            thisSprite.Angle = 0
            thisSprite.Width = GridSize.Width
            thisSprite.Height = GridSize.Height
            thisSprite.Location = thisPnt
    
            Return thisSprite
        End Function
    
    End Class
    
    Public Class ToolBar
        Public Visible As Boolean
        Public Rect As Rectangle
        Public ButtonWidth As Integer = 30
        Public Buttons As Integer = 3
        Public Sub Draw(g As Graphics)
            Using br As New SolidBrush(Color.FromArgb(50, Color.White)),
                        p As New Pen(Color.FromArgb(50, Color.Black), 2),
                        py As New Pen(Color.FromArgb(150, Color.Yellow), CSng(ButtonWidth / 7)),
                        bry As New SolidBrush(Color.FromArgb(150, Color.Yellow))
    
                g.FillRectangle(br, Rect)
                Dim rect2 As Rectangle
                Dim w As Integer = 50
                Dim x1, y1, y2 As Integer
    
                For x As Single = 0 To Buttons - 1
                    rect2 = New Rectangle(CInt(Rect.X + (x * ButtonWidth)),
                                                  Rect.Y, ButtonWidth, ButtonWidth)
                    g.DrawRectangle(p, rect2)
                    Dim t As String
                    py.EndCap = LineCap.ArrowAnchor
                    py.StartCap = LineCap.ArrowAnchor
                    g.SmoothingMode = SmoothingMode.AntiAlias
                    Select Case x
                        Case 0 : t = "Move"
                            x1 = CInt(rect2.X + (rect2.Width / 2))
                            y1 = CInt(rect2.Y + (0.1 * rect2.Height))
                            y2 = CInt(rect2.Y + (0.9 * rect2.Height))
                            g.DrawLine(py, x1, y1, x1, y2)
                        Case 1 : t = "Turn"
                            rect2.Offset(New Point(0, CInt(0.1 * w)))
                            rect2.Inflate(New Size(-4, -4))
                            g.DrawArc(py, rect2, 190, 160)
                        Case Else : t = "Fire"
                            g.DrawString("*", New Font("arial", CSng(0.7 * w)), bry, rect2.X, rect2.Y)
                    End Select
                Next
            End Using
        End Sub
    End Class
    
    Public Class Missle
        Public Location As Point
        Public MissleStep As Integer = -1
        Public MissleMsg As String = ""
        Public MissleSpriteTarget As Integer = -1
        Public ExplosionStep As Integer = -1
    End Class
    
    Public Class Sprite
        Public Name As String
        Public Style As Integer
        Public Location As PointF
        Public Angle As Single
        Public Width As Integer = 50
        Public Height As Integer = 50
    
        Public Sub DrawSprite(g As Graphics, thisPt As PointF)
            Dim gc As Drawing2D.GraphicsContainer = g.BeginContainer
            Dim rect As Rectangle = GetSpriteRectFromPoint(thisPt)
            g.TranslateTransform(thisPt.X, thisPt.Y)
            g.RotateTransform(Angle)
            g.TranslateTransform(-thisPt.X, -thisPt.Y)
    
            Select Case Style
                Case 11 'tank
                    rect.Inflate(0, -10)
                    g.DrawLine(New Pen(Color.DarkSlateGray, CSng(Width / 4)), rect.X, rect.Y, rect.X + rect.Width, rect.Y)
                    g.DrawLine(New Pen(Color.DarkSlateGray, CSng(Width / 4)), rect.X, rect.Y + rect.Height, rect.X + rect.Width, rect.Y + rect.Height)
                    rect.Inflate(-5, -5)
                    g.FillRectangle(Brushes.ForestGreen, rect)
                    g.FillEllipse(Brushes.Black, rect)
                    Dim x1 As Single = CSng(((thisPt.X + (rect.Width / 1.2))))
                    Dim y1 As Single = thisPt.Y
                    Dim x2 As Single = CSng(((thisPt.X - (rect.Width / 5))))
                    Dim y2 As Single = thisPt.Y
                    g.DrawLine(New Pen(Color.Black, CSng(Width / 6)), x1, y1, x2, y2)
    
            End Select
    
            g.EndContainer(gc)
        End Sub
    
        Public Function GetSpriteRectFromPoint(thisPt As PointF) As Rectangle
            Dim w2 As Integer = CInt(Width / 2)
            Dim h2 As Integer = CInt(Height / 2)
            Dim rect As New Rectangle(CInt(thisPt.X - w2), CInt(thisPt.Y - h2), 2 * w2, 2 * h2)
            Return rect
        End Function
    End Class
    

    This shows draw mode. LMB to move a sprite and RMB to rotate. See how the sprite data is drawn on the screen?

    Thursday, March 23, 2017 1:39 PM
  • @Tommytwotrain damn tommy this goes beyond insight that actually looks sooo "you know what curse word ill say" EPIC.

    Like i mention in a forum chat ill go through the analysis of the program before implementing. 


    WRA

    Thursday, March 23, 2017 4:45 PM
  • I hope by before the start of the easter holidays I could finish of the development stages because I still have a stack of work to do such as the write up such as the testing, evaluation of it and evaluate on the whole plus go back to the design and analysis stages. 

    WRA

    Thursday, March 23, 2017 5:00 PM
  • @Reed

    Afternoon, I just hope this isn't too much to ask could you possibly make a background design for snow and sand because I'm using this for the battle field of my game and when it does finish Ill post some screenshots to show the finalised version of it.

    Bear in mind this is the first time making a game for my coursework so I wont expect it to be perfect but to the best potential possible. 


    WRA

    Thursday, March 23, 2017 5:09 PM
  • @Tommy 

    You wrote an awful lot for your program, I gotta go through it thoroughly and try pick out the significant parts to it which demonstrate for instance where the select of the sprite indicate which tanks to attack, show how it is destroyed and remove from the grid etc. 


    WRA

    Thursday, March 23, 2017 5:16 PM
  • @Tommy 

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Sprites(1).HP = Sprites(1).HP - Sprites(2).AP
            Label1.Text = Sprites(1).HP.ToString()
            Label2.Text = Sprites(2).AP.ToString()
    
            If Sprites(1).HP <= 0 Then
                MsgBox("Murked")
                'remove sprite from list
                Sprites.Remove(Sprites(1))
            Else
                MsgBox("Still standing")
            End If
        End Sub
    

    1) It shows a major error when I try to remove the tanks from play. Here is a screenshot to show the issue.

    I dont really know if this would be of any use to you but worth a shot.

    2) Would I need to create a boolean statement to actually determine if the tank is destroyed as seen with your project because from my one when I keep pressing the button the tank hp goes onto negative numbers. 


    WRA

    Thursday, March 23, 2017 8:01 PM
  • @Tommy 

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Sprites(1).HP = Sprites(1).HP - Sprites(2).AP
            Label1.Text = Sprites(1).HP.ToString()
            Label2.Text = Sprites(2).AP.ToString()
    
            If Sprites(1).HP <= 0 Then
                MsgBox("Murked")
                'remove sprite from list
                Sprites.Remove(Sprites(1))
            Else
                MsgBox("Still standing")
            End If
        End Sub

    1) It shows a major error when I try to remove the tanks from play. Here is a screenshot to show the issue.

    I dont really know if this would be of any use to you but worth a shot.

    2) Would I need to create a boolean statement to actually determine if the tank is destroyed as seen with your project because from my one when I keep pressing the button the tank hp goes onto negative numbers. 


    WRA


    Wali,

    Thanks. Its fun to do and good practice and I get ideas for other things.

    In my example the SelectedSprite global variable represents the object with focus and the MouseDragging variable has several options for various things. As each stage is reached the variables change or increment or get turned off. You can search the example for SelectedSprite and see where it gets set in the mousedown event and etc. Its just for ideas.

    You should start new question thread now for this.  That way others get involved etc. I just posted this example here as it seemed related.

    Thursday, March 23, 2017 8:59 PM
  • Sounds like a great idea Ill forward this question here and open it to a new thread. I just felt people wouldn't reply back because today left a thread and not a reply in 7hrs. 

    WRA

    Thursday, March 23, 2017 9:04 PM