Add AI mode to custom mode

This commit is contained in:
Lncvrt committed 2026-02-21 19:30:20 -07:00
1 parent 617e38cc4d
commit a86f191b85
6 files changed
+1017 -61

No files matched your search

+253 -56
View File
@@ -45,6 +45,9 @@ public class CustomGamePlayer : MonoBehaviour {
private float antiBerryChance;
private float goldenBerryChance;
private float nothingBerryChance;
private bool useAI;
[SerializeField] private TMP_Text aiText;
void Awake() {
Instance = this;
@@ -65,66 +68,76 @@ public class CustomGamePlayer : MonoBehaviour {
antiBerryChance = customGameTempData.antiBerryChance;
goldenBerryChance = customGameTempData.goldenBerryChance;
nothingBerryChance = customGameTempData.nothingBerryChance;
useAI = customGameTempData.useAI;
Destroy(customGameTempData.gameObject);
if (useAI) aiText.gameObject.SetActive(true);
var backgroundColor = BazookaManager.Instance.GetColorSettingBackground();
Camera.main.backgroundColor = new Color(
int.Parse(backgroundColor[0].ToString()) / 255f,
int.Parse(backgroundColor[1].ToString()) / 255f,
int.Parse(backgroundColor[2].ToString()) / 255f
);
var customIconData = BazookaManager.Instance.GetCustomBirdIconData();
SpriteRenderer birdRender = bird.GetComponent<SpriteRenderer>();
if (customIconData.Selected == null) {
var birdColor = BazookaManager.Instance.GetColorSettingIcon();
var overlayColor = BazookaManager.Instance.GetColorSettingOverlay();
bird.GetComponent<SpriteRenderer>().color = new Color(
int.Parse(birdColor[0].ToString()) / 255f,
int.Parse(birdColor[1].ToString()) / 255f,
int.Parse(birdColor[2].ToString()) / 255f
);
bird.transform.GetChild(0).GetComponent<SpriteRenderer>().color = new Color(
int.Parse(overlayColor[0].ToString()) / 255f,
int.Parse(overlayColor[1].ToString()) / 255f,
int.Parse(overlayColor[2].ToString()) / 255f
if (!useAI) {
var backgroundColor = BazookaManager.Instance.GetColorSettingBackground();
Camera.main.backgroundColor = new Color(
int.Parse(backgroundColor[0].ToString()) / 255f,
int.Parse(backgroundColor[1].ToString()) / 255f,
int.Parse(backgroundColor[2].ToString()) / 255f
);
int icon = BazookaManager.Instance.GetBirdIcon();
int iconOverlay = BazookaManager.Instance.GetBirdOverlay();
if (icon == 1) {
birdRender.sprite = Tools.GetIconForUser(BazookaManager.Instance.GetAccountID() ?? 0);
} else {
birdRender.sprite = Resources.Load<Sprite>("Icons/Icons/bird_" + icon);
}
if (iconOverlay == 8) {
overlayRender.sprite = Resources.Load<Sprite>("Icons/Overlays/overlay_" + iconOverlay);
overlayRender.transform.localPosition = new UnityEngine.Vector3(-0.37f, 0.32f, 0f);
} else if (iconOverlay == 11) {
overlayRender.sprite = Resources.Load<Sprite>("Icons/Overlays/overlay_" + iconOverlay);
overlayRender.transform.localScale = new UnityEngine.Vector3(1.1f, 1.1f, 1.1f); //yea i didnt feel like doing it for all lmao
overlayRender.transform.localPosition = new UnityEngine.Vector3(-0.3141809f, 0.4324968f, 0f);
} else if (iconOverlay == 13) {
overlayRender.sprite = Resources.Load<Sprite>("Icons/Overlays/overlay_" + iconOverlay);
overlayRender.transform.localPosition = new UnityEngine.Vector3(-0.3559977f, 0.3179995f, 0f);
} else {
overlayRender.sprite = Resources.Load<Sprite>("Icons/Overlays/overlay_" + iconOverlay);
}
if (birdRender.sprite == null) {
birdRender.sprite = Resources.Load<Sprite>("Icons/Icons/bird_1");
BazookaManager.Instance.SetBirdIcon(1);
}
if (overlayRender.sprite == null && iconOverlay != 0) {
overlayRender.sprite = Resources.Load<Sprite>("Icons/Overlays/overlay_1");
BazookaManager.Instance.SetBirdOverlay(1);
}
} else if (customIconData.Selected != null)
foreach (var icon in customIconData.Purchased)
if (icon == customIconData.Selected) {
var waitingForCustomIcon = birdRender.gameObject.AddComponent<WaitingForCustomIcon>();
waitingForCustomIcon.ID = customIconData.Selected;
CustomIconLoader.Init(new[] { waitingForCustomIcon });
var customIconData = BazookaManager.Instance.GetCustomBirdIconData();
if (customIconData.Selected == null) {
var birdColor = BazookaManager.Instance.GetColorSettingIcon();
var overlayColor = BazookaManager.Instance.GetColorSettingOverlay();
bird.GetComponent<SpriteRenderer>().color = new Color(
int.Parse(birdColor[0].ToString()) / 255f,
int.Parse(birdColor[1].ToString()) / 255f,
int.Parse(birdColor[2].ToString()) / 255f
);
bird.transform.GetChild(0).GetComponent<SpriteRenderer>().color = new Color(
int.Parse(overlayColor[0].ToString()) / 255f,
int.Parse(overlayColor[1].ToString()) / 255f,
int.Parse(overlayColor[2].ToString()) / 255f
);
int icon = BazookaManager.Instance.GetBirdIcon();
int iconOverlay = BazookaManager.Instance.GetBirdOverlay();
if (icon == 1) {
birdRender.sprite = Tools.GetIconForUser(BazookaManager.Instance.GetAccountID() ?? 0);
} else {
birdRender.sprite = Resources.Load<Sprite>("Icons/Icons/bird_" + icon);
}
if (iconOverlay == 8) {
overlayRender.sprite = Resources.Load<Sprite>("Icons/Overlays/overlay_" + iconOverlay);
overlayRender.transform.localPosition = new UnityEngine.Vector3(-0.37f, 0.32f, 0f);
} else if (iconOverlay == 11) {
overlayRender.sprite = Resources.Load<Sprite>("Icons/Overlays/overlay_" + iconOverlay);
overlayRender.transform.localScale = new UnityEngine.Vector3(1.1f, 1.1f, 1.1f); //yea i didnt feel like doing it for all lmao
overlayRender.transform.localPosition = new UnityEngine.Vector3(-0.3141809f, 0.4324968f, 0f);
} else if (iconOverlay == 13) {
overlayRender.sprite = Resources.Load<Sprite>("Icons/Overlays/overlay_" + iconOverlay);
overlayRender.transform.localPosition = new UnityEngine.Vector3(-0.3559977f, 0.3179995f, 0f);
} else {
overlayRender.sprite = Resources.Load<Sprite>("Icons/Overlays/overlay_" + iconOverlay);
}
if (birdRender.sprite == null) {
birdRender.sprite = Resources.Load<Sprite>("Icons/Icons/bird_1");
BazookaManager.Instance.SetBirdIcon(1);
}
if (overlayRender.sprite == null && iconOverlay != 0) {
overlayRender.sprite = Resources.Load<Sprite>("Icons/Overlays/overlay_1");
BazookaManager.Instance.SetBirdOverlay(1);
}
} else if (customIconData.Selected != null)
foreach (var icon in customIconData.Purchased)
if (icon == customIconData.Selected) {
var waitingForCustomIcon = birdRender.gameObject.AddComponent<WaitingForCustomIcon>();
waitingForCustomIcon.ID = customIconData.Selected;
CustomIconLoader.Init(new[] { waitingForCustomIcon });
}
} else {
birdRender.sprite = Resources.Load<Sprite>("Icons/Icons/bird_1");
Destroy(overlayRender.gameObject);
var rainbowCam = Camera.main.gameObject.AddComponent<RainbowCamera>();
rainbowCam.frequency = 4f;
rainbowCam.brightness = 24;
}
lastMoveTime = Time.time;
UnityEngine.InputSystem.EnhancedTouch.EnhancedTouchSupport.Enable();
@@ -211,7 +224,190 @@ public class CustomGamePlayer : MonoBehaviour {
if (score != 0) Respawn();
}
if (antiLeft > 0f || goldenLeft > 0f) {
string[] berryTags = { "NormalBerry", "SlowBerry", "UltraBerry", "SpeedyBerry", "CoinBerry", "RandomBerry", "AntiBerry", "GoldenBerry" };
string[] berryTags = { "NormalBerry", "SlowBerry", "UltraBerry", "SpeedyBerry", "RandomBerry", "AntiBerry", "GoldenBerry", "NothingBerry" };
if (antiLeft > 0f) berryTags.Append("PoisonBerry");
foreach (string tag in berryTags) {
foreach (var berry in GameObject.FindGameObjectsWithTag(tag)) {
UnityEngine.Vector3 dir = berry.transform.position - bird.transform.position;
if (dir.magnitude < (antiLeft > 0 ? 3f : 4.5f)) {
berry.GetComponent<Rigidbody2D>().linearVelocity = dir.normalized * (antiLeft > 0 ? 5f : -5f);
ClampPosition(berry, false);
}
}
}
}
}
void MoveBirdAI() {
float screenWidth = Camera.main.orthographicSize * 2f * Camera.main.aspect;
float baseSpeed = 0.18f * (screenWidth / 20.19257f);
bool doMoveRight = false;
bool doMoveLeft = false;
bool doJump = false;
bool doBack = false;
float movespeed = baseSpeed;
if (boostLeft > 0f || speedyLeft > 0f) {
movespeed = baseSpeed * 1.39f;
} else if (slownessLeft > 0f) {
movespeed = baseSpeed * 0.56f;
}
CheckIfGrounded();
float birdX = bird.transform.position.x;
float birdY = bird.transform.position.y;
var berryScores = new System.Collections.Generic.Dictionary<string, float> {
{ "NormalBerry", 1f },
{ "UltraBerry", 5f },
{ "SpeedyBerry", 10f },
{ "RandomBerry", 0f },
{ "GoldenBerry", 4f },
{ "PoisonBerry", -100f },
{ "SlowBerry", -1f },
{ "AntiBerry", -10f },
};
var allBerries = new System.Collections.Generic.List<(float x, float y, float score)>();
foreach (var kvp in berryScores) {
foreach (var b in GameObject.FindGameObjectsWithTag(kvp.Key)) {
allBerries.Add((b.transform.position.x, b.transform.position.y, kvp.Value));
}
}
float collectRadius = 1.5f;
bool WouldCollideAtX(float testX, float berryX, float berryY, float radius) {
float dx = Mathf.Abs(testX - berryX);
float dy = Mathf.Abs(birdY - berryY);
return dx < radius && dy < radius;
}
bool PathHasDanger(float targetX) {
foreach (var (bx, by, score) in allBerries) {
if (score >= 0f) continue;
float dy = Mathf.Abs(by - birdY);
if (dy >= collectRadius) continue;
float pathMin = Mathf.Min(birdX, targetX);
float pathMax = Mathf.Max(birdX, targetX);
if (bx + collectRadius > pathMin && bx - collectRadius < pathMax) return true;
}
return false;
}
float closestBadX = float.MaxValue;
float closestBadDist = float.MaxValue;
float dodgeLookahead = collectRadius + movespeed * 8f;
foreach (var (bx, by, score) in allBerries) {
if (score >= 0f) continue;
float dy = Mathf.Abs(by - birdY);
if (dy >= collectRadius) continue;
float dx = Mathf.Abs(bx - birdX);
if (dx < dodgeLookahead && dx < closestBadDist) {
closestBadDist = dx;
closestBadX = bx;
}
}
bool inDanger = closestBadDist < float.MaxValue;
if (inDanger) {
doMoveLeft = closestBadX >= birdX;
doMoveRight = closestBadX < birdX;
} else {
var clusters = new System.Collections.Generic.List<(float x, float y, float score)>();
var used = new bool[allBerries.Count];
float clusterRadius = 1.8f;
for (int i = 0; i < allBerries.Count; i++) {
if (used[i]) continue;
var (ax, ay, aScore, _) = (allBerries[i].x, allBerries[i].y, allBerries[i].score, 0);
float wX = ax * Mathf.Abs(aScore), wY = ay, total = aScore, wTotal = Mathf.Abs(aScore);
int count = 1;
used[i] = true;
for (int j = i + 1; j < allBerries.Count; j++) {
if (used[j]) continue;
var (bx, by, bScore, _) = (allBerries[j].x, allBerries[j].y, allBerries[j].score, 0);
float d = Mathf.Sqrt((bx - ax) * (bx - ax) + (by - ay) * (by - ay));
if (d < clusterRadius) {
wX += bx * Mathf.Abs(bScore); wY += by;
total += bScore; wTotal += Mathf.Abs(bScore);
count++; used[j] = true;
}
}
clusters.Add((wTotal > 0f ? wX / wTotal : ax, wY / count, total));
}
float bestScore = 0f;
float bestX = float.MaxValue;
bool foundTarget = false;
foreach (var (cx, cy, cs) in clusters) {
if (cs <= 0f) continue;
if (PathHasDanger(cx)) continue;
float dist = Mathf.Abs(cx - birdX);
float adjusted = cs - dist * 0.05f;
if (adjusted > bestScore) {
bestScore = adjusted;
bestX = cx;
foundTarget = true;
}
}
if (foundTarget) {
float alignTolerance = collectRadius * 0.6f;
if (birdX < bestX - alignTolerance) {
doMoveRight = true;
} else if (birdX > bestX + alignTolerance) {
doMoveLeft = true;
} else {
bool goodBerryAbove = false;
foreach (var (bx, by, score) in allBerries) {
if (score > 0f && by > birdY && WouldCollideAtX(birdX, bx, by, collectRadius))
goodBerryAbove = true;
}
if (goodBerryAbove) doJump = true;
}
}
}
if (Application.isMobilePlatform) {
var touches = UnityEngine.InputSystem.EnhancedTouch.Touch.activeTouches;
for (int i = 0; i < touches.Count; i++) {
var pos = touches[i].screenPosition;
UnityEngine.Vector3 clickPosition = Camera.main.ScreenToWorldPoint(new UnityEngine.Vector3(pos.x, pos.y, 0f));
clickPosition.z = 0f;
if (pauseButton.GetComponent<HoldableButton>().isPressed) doBack = true;
}
}
if (doMoveLeft && !doMoveRight) {
lastMoveTime = Time.time;
bird.transform.position += new UnityEngine.Vector3(-movespeed, 0f, 0f);
ClampPosition(bird);
bird.transform.localScale = new UnityEngine.Vector3(1.35f, 1.35f, 1.35f);
}
if (doMoveRight && !doMoveLeft) {
lastMoveTime = Time.time;
bird.transform.position += new UnityEngine.Vector3(movespeed, 0f, 0f);
ClampPosition(bird);
bird.transform.localScale = new UnityEngine.Vector3(-1.35f, 1.35f, 1.35f);
}
if (doJump && isGrounded) {
lastMoveTime = Time.time;
AudioSource.PlayClipAtPoint(Resources.Load<AudioClip>("Sounds/Jump"), Camera.main.transform.position, 0.75f * BazookaManager.Instance.GetSettingSFXVolume());
if (boostLeft > 0f || speedyLeft > 0f) {
rb.linearVelocity = UnityEngine.Vector2.up * 12f;
} else if (slownessLeft > 0f) {
rb.linearVelocity = UnityEngine.Vector2.up * 6f;
} else {
rb.linearVelocity = UnityEngine.Vector2.up * 9f;
}
}
if (doBack) {
TogglePause();
}
if (antiLeft > 0f || goldenLeft > 0f) {
string[] berryTags = { "NormalBerry", "SlowBerry", "UltraBerry", "SpeedyBerry", "RandomBerry", "AntiBerry", "GoldenBerry", "NothingBerry" };
if (antiLeft > 0f) berryTags.Append("PoisonBerry");
foreach (string tag in berryTags) {
foreach (var berry in GameObject.FindGameObjectsWithTag(tag)) {
@@ -244,7 +440,8 @@ public class CustomGamePlayer : MonoBehaviour {
void FixedUpdate() {
SpawnBerries();
if (!pausePanel.activeSelf) {
MoveBird();
if (useAI) MoveBirdAI();
else MoveBird();
if (boostLeft > 0f) {
boostLeft -= Time.deltaTime;
boostText.text = "Boost expires in " + string.Format("{0:0.0}", boostLeft) + "s";
@@ -10,6 +10,7 @@ public class CustomGameTempData : MonoBehaviour {
public float antiBerryChance;
public float goldenBerryChance;
public float nothingBerryChance;
public bool useAI;
void Awake() {
DontDestroyOnLoad(gameObject);
+4
View File
@@ -26,6 +26,7 @@ public class PlayMenu : MonoBehaviour {
[SerializeField] private TMP_InputField antiBerryChance;
[SerializeField] private TMP_InputField goldenBerryChance;
[SerializeField] private TMP_InputField nothingBerryChance;
[SerializeField] private Toggle useAiToggle;
[SerializeField] private TMP_Text validateTotalText;
@@ -59,6 +60,7 @@ public class PlayMenu : MonoBehaviour {
antiBerryChance.text = defaultAntiBerryChance.ToString() + "%";
goldenBerryChance.text = defaultGoldenBerryChance.ToString() + "%";
nothingBerryChance.text = defaultNothingBerryChance.ToString() + "%";
useAiToggle.isOn = false;
ValidateTotal();
if (DiscordRPCHandler.Instance != null)
DiscordRPCHandler.Instance.UpdateRPC("Picking what mode they want to play", "");
@@ -175,6 +177,7 @@ public class PlayMenu : MonoBehaviour {
customGameTempData.antiBerryChance = GetValueFrom(antiBerryChance);
customGameTempData.goldenBerryChance = GetValueFrom(goldenBerryChance);
customGameTempData.nothingBerryChance = GetValueFrom(nothingBerryChance);
customGameTempData.useAI = useAiToggle.isOn;
await SceneManager.LoadSceneAsync("CustomGamePlayer");
});
autoButton.onClick.AddListener(async () => {
@@ -219,6 +222,7 @@ public class PlayMenu : MonoBehaviour {
DiscordRPCHandler.Instance.UpdateRPC("Picking what mode they want to play", "");
if (Tools.GetLevelInfo().level < 5) {
useAiToggle.gameObject.SetActive(false);
customButton.interactable = false;
customButton.transform.GetChild(0).GetComponent<TMP_Text>().text += "\n<size=12>You need level 5 or higher to access this</size>";
}