CAGD 470 - Sprint 5

Onto another sprint blog. For the most part, I worked on new spells, which was much needed to add variety to the gameplay.


First of all, I reworked the Rot spell effect. Now, if an enemy is rotted and a card is discarded, they will take damage (Figure 1).


Figure 1. This is in the Deck’s discard function.


Typically, I do three spells at a time. For the first batch of three, I did some lightning spells. I started them last sprint, and I finished them shortly after sprint five started.

  • Lightning strike: deal heavy damage to a very small area wherever the mouse cursor is located. After a short delay, apply shock. If there are lightning cards in the player's hand, deal more damage.

  • Charge: apply shock to all targets in an area.

  • Quick thinking: perform the next spell cast X + 1 times (one shortly after another), where X is the number of lightning cards in hand.


I had a lot of trouble knowing where the mouse position was relative to the world, rather than the screen. Normally, you could do Camera.main.ScreenToWorldPoint(Input.mousePosition), but since we’re doing a 2D game and we’re using the new Unity Input system, so that’s not going to work. Given that this kind of functionality is needed for many spells, I decided to give a protected Vector3 function to Spell.cs, so that any spell can teleport itself at the mouse position.

See implementation in Figure 2.


Figure 2. Notice now I need to do Mouse.current.position.ReadValue() - instead of Input.mousePosition, to get the mouse’s position relative to the screen. Then, I reset the z-axis of the mouse, so that it is at the same level as the camera. Otherwise, the spell would be placed in strange, unpredictable locations. I probably didn’t have to return worldPoint, but do use the return value for readability elsewhere in the code.


The spell, Quick Thinking, was tricky since to spawn the following spell multiple times, there needs to be some sort of communication back up to the Deck script. Deck creates the spell objects. After some trial and error, here’s how it works: Quick Thinking itself increments Deck’s numTimesToCast variable by X+1, where X is the number of lightning cards in hand. Then, when the next spell is cast, it will check the value of numTimesToCast. If numTimesCast is one, cast your spell as you normally would. Otherwise, start a coroutine. (See Figures 3 & 4).


Figure 3. This is shortly after the player left-clicks to activate a spell.


Figure 4. The coroutine is not much different. It simply calls the same function numTimesToCast times, once every second. Afterward, it forces numTimesCast to its default value of one.


I then updated the room rewards to work. You see, I was given a card a sprint or two ago to create the framework of what would be a reward system. After all the enemies in a room die and there are no more enemies to spawn, then a reward is spawned. Before this, the reward was simply a chest. Upon interacting with the chest, it disappeared. That’s it. Pretty underwhelming. Now, upon interacting with a chest, a random card is added to your deck. A reward could alternatively be a heart, which heals the player by 25. (See Figure 5.)


Figure 5. Notice how the player’s health was brought down to 75, and then upon interacting with the heart, the player is healed back to 100.


After the reward system was functional, I began to work on the next three spells of which were also Lightning.

  • Orb: a slow-moving sphere that damages units around it every second.

  • Lightning Jump: teleport to the mouse position and deal damage to enemies in between your old and new position.

  • Storm Unleashed: cast lightning strike 5 times.


My first thought upon looking at these was how they would work with the Quick Thinking spell. Theoretically, you could have three lightning cards in your hand. If you cast Quick Thinking with three lightning cards in your hand, you will cast the next card four times (3 + 1). So, if you follow that up with a Storm Unleashed, you will be casting lightning strike 4 x 5 = 20 times! And if an enemy is Shocked, they will be taking double damage. That’s OP.


Anyway, Orb was more complicated than I initially thought, since I imagined a plasma globe everyone wanted as a kid. How it works is that every tenth of a second or so, a trail renderer will move towards a new target, and deal damage to that target - as long as the target is within the orb’s range. (See Figures 6 & 7).


Figure 6. Woah so cool.


Figure 7. Eh, close enough.


The Lightning Jump is probably my favorite spell I’ve done so far. The player is teleported to the mouse position immediately, but the spell’s collider is lerp’ed towards the player’s position. That way, the enemies in between the old and new position of the player will take damage. I also use RaycastAll to prevent the player from going out of bounds. There is another trail renderer attached for an admittedly programmer-grade visual effect. (See Figure 8).


Figure 8. Turned out looking and feeling quite good in my opinion.


For the final three spells, here’s what I had:

  • Blizzard: create a large area of effect that slows the enemy and deals damage over time.

  • Nova: create a burst area of effect that freezes enemies near the player.

  • Flurry: create many tiny projectiles that seek the nearest enemy.


Blizzard implies a Slow status effect, so I added Slow to the status effect system I created for enemies. Given the flexibility of the system, it was relatively easy to implement this spell. Same with Nova.


For flurry, I also used linear interpolation to move towards the enemy. I created some kind of turret-looking object that spawned many projectiles. (See Figure 9). Turns out this isn’t really what Miles (the lead) had in mind, so I had to do something a little more involved.


Figure 9. Old flurry. Looks a little odd.


Miles wanted the flurry spell to sort of ‘curve’ towards the enemy. Furthermore, he wanted it to spawn where the player is, rather than creating some kind of non-moving turret. Immediately, I thought of what I recently learned in CAGD 380: Bezier curves.


The way I implemented this is pretty straightforward. I “interpolate” the projectile from the origin (the player position) to the target (the enemy). The way I curve the projectile is by randomizing some “middle point” that will skew the path. (See Figure 10). The final result is shown in Figure 11.


Figure 10.



Figure 11. New flurry.


Next sprint, I will likely be creating more spells, as well as fine-tuning what’s already in the project. Here is the list of cards completed:

  • As a designer, I would like 3 Lightning Spells to be added. (3)

  • As a designer, I would like rot to be changed to damage whenever a card is added to discard. (1)

  • As a player, I would like rewards to spawn when a room is completed. (1)

  • As a designer, I would like 3 Lightning Spells to be added. (3)

  • As a designer, I would like 3 Frost Spells to be added. (3)

  • As a designer, I would like an update to seek from spells. (1)


See you in sprint 6.


No comments:

Post a Comment