Killing Those Blobs (Cosplore3D Pt:8)
Tags: go, gamedev, learning
Published: 2024-02-09 01:30:00

## Intro
This is a new series following [Cosplore3D](https://github.com/Chig-Beef/Cosplore3D), a raycaster game to learn 3D graphics. This project is part of 12 Months 12 Projects, a challenge I set myself.
We just did a bunch of work on the first level, Ankaran, but the gameplay is a bit dry, so we need to start actually implementing features that make the game fun.

## Shooting Enemies
When we click, we should see if we shot an enemy.
```golang
func (w *Weapon) shoot(p *Player, enemies []*Enemy) {
    var e *Enemy
    var dx, dy, dis, angle float64

    w.curMag--

    for i := 0; i < len(enemies); i++ {
        e = enemies[i]

        dx = e.x - p.x
        dy = e.y - p.y
        dis = math.Sqrt(math.Pow(dx, 2) + math.Pow(dy, 2))
        angle = to_degrees(math.Acos(dx / dis))

        if math.Asin(dy/dis) < 0 {
            angle = -angle
        }

        // How much to the left or right of the player the enemy is
        angle -= p.angle
        angle = bound_angle(angle)

        if angle < w.bulletSize || angle > 360-w.bulletSize {
            e.health -= w.damage
            return
        }
    }
}
```
That looks pretty simple, right? All we're doing is looking through all enemies (although, once we've successfully shot an enemy we don't keep looking. We calculate the angle between the enemy and the player, and then if the angle is small enough then we hit the enemy.

## Enemies Follow The Player
Now it was fun killing all the enemies, then grabbing the cosmium, but it really doesn't mean anything against static beings. So now we should make it so that the enemy tries to follow the player.
```golang
func (e *Enemy) follow_target() {
    var dx, dy, dis, angle float64

    dx = e.x - e.target.x
    dy = e.y - e.target.y
    dis = math.Sqrt(math.Pow(dx, 2) + math.Pow(dy, 2))
    angle = to_degrees(math.Acos(dx / dis))

    if math.Asin(dy/dis) < 0 {
        angle = -angle
    }

    // How much to the left or right of the player the enemy is
    angle = bound_angle(angle)

    e.x -= math.Cos(to_radians(angle)) * e.speed
    e.y -= math.Sin(to_radians(angle)) * e.speed

    e.angle = angle
}
```

## More Ammo
We have an `Item` `struct`, so we're going to use that for ammo as well. We need a way to give the player ammo whenever we collide with an ammo item. Here's my solution.
```golang
type Action func(*Game)

func giveAmmo(g *Game) {
    g.player.weapon.curMag += 10
    if g.player.weapon.curMag > g.player.weapon.mag {
        g.player.weapon.curMag = g.player.weapon.mag
    }
}
```
We can create a type of function that takes a pointer to the `Game` as input. In this way, we can more easily give functionality to `Item`s, but quite literally giving them functions.

## Enemies Fight Back
Now we need to get the enemy to damage the player when it's too close.
```golang
func (e *Enemy) attack_target() {
    var dx, dy, dis float64

    dx = e.x - e.target.x
    dy = e.y - e.target.y
    dis = math.Sqrt(math.Pow(dx, 2) + math.Pow(dy, 2))

    if dis < e.attackRange {
        e.attackCooldown--
        if e.attackCooldown == 0 {
            e.target.health -= e.damage
            e.attackCooldown = e.roa
        }
    }
}
```
Using `attackCooldown`, the enemy has to wait to attack again. And playing with this feature, I do lose health, and eventually my HUD shows no hearts.

## Dying
What's the point of losing health if you can't die? So no we need to do something once we die. For now, I think we'll exit the game.
```golang
// Attempt to kill
if e.target.health <= 0 {
    os.Exit(0)
}
```
I know that's quite a basic way to die, but I don't really know what I want to do when the player dies yet, whether I want it to instantly restart level, go back to some sort of menu, or anything like that, so for now this works and at least we have the logic.

## Next
This gameplay is going quite well, but I feel too powerful being able to walk through walls, so we will have to fix that soon, most likely in the next post.