New Doodad: Blue Bird

* The blue bird follows the same base AI as the red bird (it has a
  target altitude that it tries to maintain, and it will dive at the
  player) but the blue bird flies in a sine wave pattern around its
  target altitude. It also has a longer scan radius to search for the
  player than the red bird.
* The sine wave pattern of the blue bird means you may fly under its
  radar depending how high it is on average.

Cheat codes that replace the player character are refactored to make
it easier to extend, and new cheats have been added:

* super azulian: play as the Red Azulian.
* hyper azulian: play as the White Azulian.
* bluebird: play as the new Bird (blue).
This commit is contained in:
Noah 2022-04-30 17:59:55 -07:00
parent 66382739bb
commit 0ed5d6ae0c
14 changed files with 68 additions and 8 deletions

View File

@ -2,9 +2,17 @@ ALL: build
.PHONY: build
build:
doodad convert -t "Bird (red)" left-1.png left-2.png right-1.png right-2.png \
dive-left.png dive-right.png bird-red.doodad
doodad convert -t "Bird (red)" red/left-1.png red/left-2.png red/right-1.png \
red/right-2.png red/dive-left.png red/dive-right.png \
bird-red.doodad
doodad install-script bird.js bird-red.doodad
doodad edit-doodad --tag "color=red" bird-red.doodad
doodad convert -t "Bird (blue)" blue/left-1.png blue/left-2.png blue/right-1.png \
blue/right-2.png blue/dive-left.png blue/dive-right.png \
bird-blue.doodad
doodad install-script bird.js bird-blue.doodad
doodad edit-doodad --tag "color=blue" bird-blue.doodad
# Tag the category for these doodads
for i in *.doodad; do\

View File

@ -1,8 +1,26 @@
// Bird
// Bird (red and blue)
/*
Base A.I. behaviors (red bird) are:
- Tries to maintain original altitude in level and flies left/right.
- Divebombs the player to attack, then climbs back to its original
altitude when it hits a floor/wall.
Blue bird:
- Flies in a sine wave pattern (its target altitude fluctuates
around the bird's original placement on the level).
- Longer aggro radius to dive.
*/
let speed = 4,
Vx = Vy = 0,
altitude = Self.Position().Y; // original height in the level
color = Self.GetTag("color"), // informs our A.I. behaviors
searchStep = 12 // pixels to step while searching for a player
searchLimit = color === "blue" ? 24 : 12, // multiples of searchStep for aggro radius
altitude = Self.Position().Y, // original height in level
targetAltitude = altitude; // bird's target height to maintain
let direction = "left",
lastDirection = "left";
@ -42,6 +60,11 @@ function main() {
lastSampled = Point(0, 0);
setInterval(() => {
// Run blue bird A.I. if we are blue: moves our target altitude along a sine wave.
if (color === "blue") {
AI_BlueBird();
}
// Sample how far we've moved to detect hitting a wall.
if (sampleTick % sampleRate === 0) {
let curP = Self.Position()
@ -65,8 +88,8 @@ function main() {
// If we are not flying at our original altitude, correct for that.
let curV = Self.Position();
Vy = 0.0;
if (curV.Y != altitude) {
Vy = curV.Y < altitude ? 1 : -1;
if (curV.Y != targetAltitude) {
Vy = curV.Y < targetAltitude ? 1 : -1;
}
// Scan for the player character and dive.
@ -114,9 +137,9 @@ function AI_ScanForPlayer() {
return
}
let stepY = 12, // number of pixels to skip
let stepY = searchStep, // number of pixels to skip
stepX = stepY,
limit = stepX * 20, // furthest we'll scan
limit = stepX * searchLimit, // furthest we'll scan
scanX = scanY = 0,
size = Self.Size(),
fromPoint = Self.Position();
@ -147,6 +170,35 @@ function AI_ScanForPlayer() {
return;
}
// Sine wave controls for the Blue bird.
var sineLimit = 32,
sineCounter = 0,
sineDirection = 1,
sineFrequency = 5, // every 500ms
sineStep = 16;
// A.I. Subroutine: sine wave pattern (Blue bird).
function AI_BlueBird() {
// The main loop runs on a 100ms interval, control how frequently
// to adjust the bird's target velocity.
if (sineCounter > 0 && (sineCounter % sineFrequency) > 1) {
sineCounter++;
return;
}
sineCounter++;
targetAltitude += sineStep*sineDirection;
// Cap the distance between our starting altitude and sine-wave target.
if (targetAltitude < altitude && altitude - targetAltitude >= sineLimit) {
targetAltitude = altitude - sineLimit;
sineDirection = 1
} else if (targetAltitude > altitude && targetAltitude - altitude >= sineLimit) {
targetAltitude = altitude + sineLimit;
sineDirection = -1
}
}
// If under control of the player character.
function player() {
let playerSpeed = 12,

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 959 B

After

Width:  |  Height:  |  Size: 959 B

View File

Before

Width:  |  Height:  |  Size: 989 B

After

Width:  |  Height:  |  Size: 989 B

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1022 B

After

Width:  |  Height:  |  Size: 1022 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB