每次到了做作业的时候,总觉得漫漫学习夜需要点食物陪伴,于是这次做了一条能够吃了彩虹食物变大变强的鱼儿,和在代码海洋喂鲨鱼的我不同,我要让它称霸这片渔场。
这是一个简单的小游戏,玩法是:玩家操控小鱼去吃掉那些当前可以食用的鱼食,以此来不断升级得分并将小鱼变大变色,最后获得游戏的胜利。主要通过页面设计,游戏难易等级设定,增添交互的趣味性。
该段代码判断是否点击中 start 键
if (mousePressed && startTimer > 30) {
if (abs(mouseX - 2 * width / 3) < 150 && (abs(mouseY - height / 2) < 150)) {
x = mouseX;
y = mouseY;
}
}
如点击成功,则载入游戏场景;
}
if (x != 0 && y != 0) {
fill(0);
size *= 1.05;
ellipse(x, y, size, size);
if (size >= 1200) {
colorList = new int[5][1];
loadColors("one");
drawBar();
b.redraw();
p.displayLives();
fill(0, fadeAgain);
rect(0, 0, width, height);
fadeAgain *= 0.95;
if (fadeAgain <= 10)
stages.moveToNextStage();
}
}
在游戏开始之前,先显示当前 游戏难度等级 、状态栏(FrenzyTime进度条:蓄满之后一定时间内得分×2;当前分数;历史最高得分;当前可食用鱼食类型;生命值)。
class Bar {
float percent = 0; // 得分进度条
boolean frenzy; // 狂暴模式
void displayScore() {
fill(245, 90, 61);
textAlign(LEFT, TOP); // 左上对齐
font = createFont(fName, 26); // 载入字体
textFont(font);
int posX = 250; // 分数栏位置
int posY = barHeight / 2 - 15;
text("score: " + score, posX, posY);
text("high: " + highScore, posX + 160, posY);
}
void redraw() {
stroke(10);
strokeWeight(2);
strokeCap(ROUND);
rect(30, 30, 150, 20);
noStroke();
fill(0);
if (percent <= 0)
percent = 0;
if (percent >= 100) {
percent = 100;
frenzy = true;
}
if (frenzy) {
displayFrenzy();
if (percent <= 0)
frenzy = false;
} else
percent -= 0.03;
rect(34, 34, 142*percent*0.01, 13);
displayScore();
displayFish();
}
void addPercent(float s) {
percent += s * 0.2;
}
void displayFrenzy() {
percent -= 0.1;
textAlign(CENTER);
font = createFont(fName, 50);
textFont(font);
fill(#FFCC00);
text("FRENZY", width / 2, barHeight + 100);
}
void displayFish() {
int x = width / 2 + 100;
int y = barHeight / 2;
Fish[] fish = new Fish[5];
for (int i = 0; i < 5; i++) {
int s = (i + 1) * 10;
int move = (s + 10) / 2;
fish[i] = new Fish(s, x, y, true);
x += s / 2 + 2;
stroke(0);
strokeWeight(1);
if (p.size >= s && p.size < s + 10)
line(x, y - move, x, y + move);
noStroke();
x += move + 3;
}
}
}
void displayLives() {
int temp = 0;
int pos = 900;
text("HP:" , 840, 23);
while (temp < 3) {
strokeWeight(1);
stroke(255, 0, 0);
if (temp < lives)
fill(255, 0, 0);
else {
noFill();
}
ellipse(pos, barHeight / 2, 25, 25);
noStroke();
temp+=1;
pos+=30;
}
}
class Bubble {
float size;
PVector position = new PVector();
boolean gone;
float speed;
Bubble() {
size = random(2, 13);
position.x = random(0, width-300);
position.y = height+size;
speed = size*2/5;
}
void update() {
stroke(255);
strokeWeight(1);
fill(166, 223, 248, 100);
ellipse(position.x, position.y, size, size);
position.y-=speed;
if (position.y<-2*size) {
gone = true;
}
}
}
void redraw() {
noStroke();
fill(R,G,B);
triangle(centerX,centerY, centerX-size, centerY-size/3, centerX-size, centerY+size/3);
ellipse(centerX, centerY, size*1.15, size);
colorMode(RGB) ;
fill(255);
ellipse(centerX+size/5,centerY,size/3,size/3);
fill(0);
ellipse(centerX+size/4,centerY,size/5,size/5);
triangle(centerX-size/2,centerY, centerX-size/4, centerY-size/4, centerX-size/4, centerY+size/4);
}
用于计算鱼食和鱼的关系,如果鱼食比鱼体积大则会以一定速度向鱼冲刺,否则会以一定速度远离鱼。
void update() {
if (nextLevelAnimation) {
accelX += 20 / size * dirX * -0.5;
accelY = 0;
} else {
float deltaX = p.centerX-centerX;
float deltaY = p.centerY-centerY;
changeX(deltaX);
changeY(deltaY);
smaller = p.size > this.size;
if (smaller) {
if (within(deltaX, deltaY, (int)size * 4)) {
accelX += 20 / size * dirX * -0.5;
accelY += 20 / size * dirY * -0.5;
}
} else {
if (within(deltaX, deltaY, (int)size * 4)) {
//acceleration is greater the smaller it is
accelX += 20 / size * dirX * 1;
accelY += 20/ size * dirY * 1;
}
}
}
if (display) {
speedX = 0;
speedY = 0;
accelX = 0;
accelY = 0;
}
centerX += (speedX + accelX) / frameRate * 1.5;
centerY += (speedY + accelY) / frameRate * 1.5;
redraw();
}
boolean touching(Fish t) {
float distance = p.size / 2 + t.size / 2;
boolean x = abs(t.centerX - p.centerX) < distance;
boolean y = abs(t.centerY - p.centerY) < distance;
return x && y;
}
boolean canEat(Fish t) {
return touching(t) && (t.size < p.size) && !p.lifeAnimation;
}
boolean canBeEaten(Fish t) {
return touching(t) && (t.size >= p.size) && !p.lifeAnimation && !(p.invulnerable > 0);
}
void updateFish() {
for (Fish f : fishies) {
f.update();
if (f.outOfBounds()) {
fishies.remove(f);
break;
}
if (canEat(f)) {
eat(f);
if (b.frenzy)
score += f.size * multi * 2;
else
score += f.size * multi;
break;
}
if (canBeEaten(f)) {
p.loseLife();
p.invulnerable += 270;
break;
}
}
}
void absorb(Powerup pow) {
if (random(2) < 1) {
if (p.lives < 3)
p.lives++;
} else if (random(500) < 1) {
score = (round(score * 1.5));
if (b.frenzy)
score = (round(score * 1.5));
} else if (random(10) < 1) {
p.speedBoost = 50;
p.springing = 0.05;
} else {
p.invulnerable = 250;
}
powers.remove(pow);
}
void eat(Fish f) {
p.upsize((f.size + 5) / p.size * 0.25);
if (!b.frenzy)
b.addPercent((f.size + 5) / p.size * f.size * multi);
fishies.remove(f);
}
if (win) {
winScreen();
} else if (!(p.dead) && !win) {
fillBlack();
p.update();
updatePowers();
updateFish();
nextLevelCheck();
if (!nextLevelAnimation)
addFish();
addPowers();
//menu bar
drawBar();
b.redraw();
p.displayLives();
} else
gameOver();
}
void redraw() {
stroke(10);
strokeWeight(2);
strokeCap(ROUND);
rect(30, 30, 150, 20);
noStroke();
fill(0);
if (percent <= 0)
percent = 0;
if (percent >= 100) {
percent = 100;
frenzy = true;
}
if (frenzy) {
displayFrenzy();
if (percent <= 0)
frenzy = false;
} else
percent -= 0.03;
rect(34, 34, 142*percent*0.01, 13);
displayScore();
displayFish();
}
无敌:空格
变大:Q
威慑:W
嘲讽:E
加速:R
1.按空格 ( 无敌)变成无敌模式
2.按Q ( 变大)迅速变大通关
3.按R ( 加速)小鱼快速移动,追逐食物躲闪攻击
1.按W ( 威慑),让可食鱼食加速离开
2.按E ( 嘲讽),增加有攻击性鱼食的攻击范围,加速移动
泡泡、鱼食的生成,特殊鱼食的出现和奖励都用到了随机数这个知识点
用向量来使满足条件的鱼食移动,给游戏增加难度和趣味性
由于功能比较细小繁多,为避免重复和单调,使用继承提高了代码的复用性。