作业要求完成情况
- 向量的运动速度:方块的运动
- 粒子系统:方块爆炸后粒子特效
- 碰撞事件:方块之间的碰撞
代码详解
方块运动
void move()
{
if (player != null && player.alive && canShoot && dist(player.position.x, player.position.y, position.x, position.y) <= sight/2)
{
inSight = true;
if (player.position.x > position.x)
{
velocity.x = lerp(velocity.x, speed, 0.01);
} else if (player.position.x < position.x)
{
velocity.x = lerp(velocity.x, -speed, 0.01);
} else
{
velocity.x = lerp(velocity.x, 0, 0.1);
}
if (player.position.y > position.y)
{
velocity.y = lerp(velocity.y, speed, 0.01);
} else if (player.position.y < position.y)
{
velocity.y = lerp(velocity.y, -speed, 0.01);
} else
{
velocity.y = lerp(velocity.y, 0, 0.1);
}
} else
{
if (canShoot)
cooldown = maxCoolDown;
inSight = false;
velocity.x += random(-0.1, 0.1);
velocity.y += random(-0.1, 0.1);
}
velocity.limit(speed);
}
碰撞实体
int collides(Entity E)
{
if (this.ID != E.ID)
{
float A_top = this.position.y - this.dimentions.y/2;
float A_right = this.position.x + this.dimentions.x/2;
float A_bot = this.position.y + this.dimentions.y/2;
float A_left = this.position.x - this.dimentions.x/2;
float B_top = E.position.y - E.dimentions.y/2;
float B_right = E.position.x + E.dimentions.x/2;
float B_bot = E.position.y + E.dimentions.y/2;
float B_left = E.position.x - E.dimentions.x/2;
if(A_bot > B_top && A_left < B_right && A_right > B_left && this.position.y < B_top)
{
return 1;
}
if(A_left < B_right && A_top < B_bot && A_bot > B_top && this.position.x > B_right)
{
return 2;
}
if(A_top < B_bot && A_left < B_right && A_right > B_left && this.position.y > B_bot)
{
return 3;
}
if(A_right > B_left && A_top < B_bot && A_bot > B_top && this.position.x < B_left)
{
return 4;
}
}
return -1;
}
碰撞处理
void handleCollision()
{
for (Entity E : walls)
{
if (player.alive && player.collides(E) != -1)
{
switch(player.collides(E))
{
case 1:
player.velocity.y = 0;
player.position.y -= 2;
break;
case 2:
player.velocity.x = 0;
player.position.x += 2;
break;
case 3:
player.velocity.y = 0;
player.position.y += 2;
break;
case 4:
player.velocity.x = 0;
player.position.x -= 2;
break;
}
}
for (Entity EN : enemies)
{
if (EN.collides(E) != -1)
{
switch(EN.collides(E))
{
case 1:
EN.velocity.y *= -1;
EN.position.y -= 1;
break;
case 2:
EN.velocity.x *= -1;
EN.position.x += 1;
break;
case 3:
EN.velocity.y *= -1;
EN.position.y += 1;
break;
case 4:
EN.velocity.x *= -1;
EN.position.x -= 1;
break;
}
}
}
for (int i = bullets.size() - 1; i >= 0; i--)
{
if (E.special == -1 && bullets.get(i).collides(E) != -1)
{
bullets.get(i).onRemoval();
bullets.remove(i);
continue;
} else if (E.special == 2 && bullets.get(i).collides(E) != -1)
{
switch(bullets.get(i).collides(E))
{
case 1:
bullets.get(i).velocity.y *= -1;
bullets.get(i).position.y -= 2;
break;
case 2:
bullets.get(i).velocity.x *= -1;
bullets.get(i).position.x += 2;
break;
case 3:
bullets.get(i).velocity.y *= -1;
bullets.get(i).position.y += 2;
break;
case 4:
bullets.get(i).velocity.x *= -1;
bullets.get(i).position.x -= 2;
break;
}
}
if (player.alive && bullets.get(i).collides(player) != -1)
{
bullets.remove(i);
player.lives--;
}
}
}
爆炸处理
if (player.lives <= 0)
{
player.alive = false;
player.lives = 1;
player.velocity.setMag(1);
for (int i = 0; i < 25; i++)
{
Entity P = new Entity(player.position.x, player.position.y);
P.dimentions.x = 5;
P.dimentions.y = 5;
P.filler = player.filler;
P.velocity.x = random(-2, 2);
P.velocity.y = random(-2, 2);
P.velocity.add(player.velocity);
particles.add(P);
}
}
if (player.alive) {
for (int i = enemies.size()-1; i >= 0; i--)
{
if (player.collides(enemies.get(i)) != -1)
{
if (enemies.get(i).parent != null)
enemies.get(i).parent.children.remove(enemies.get(i));
enemies.remove(i);
}
}
}
}
关卡设置
void loadWalls(int levels)
{
switch(levels)
{
case 0:
stage.Width = 800;
stage.Height = 600;
player = new Player(stage.Width/4, stage.Height/2);
enemies.add(new Enemy(stage.Width*3/4, stage.Height/2));
edges(stage.Width, stage.Height);
walls.add(new Wall(stage.Width/2, stage.Height/2, 20, stage.Height*2/3, -1));
break;
case 1:
stage.Width = 800;
stage.Height = 600;
player = new Player(stage.Width/4, stage.Height/2);
enemies.add(new Enemy(stage.Width*3/4, stage.Height*1/4));
enemies.add(new Enemy(stage.Width*3/4, stage.Height*3/4));
edges(stage.Width, stage.Height);
walls.add(new Wall(stage.Width/2, stage.Height/2, 20, stage.Height*2/3, -1));
break;
case 2:
stage.Width = 800;
stage.Height = 600;
player = new Player(stage.Width/4, stage.Height/2);
enemies.add(new Enemy(stage.Width*3/4, stage.Height/4));
enemies.add(new Enemy(stage.Width*3/4, stage.Height*3/4));
edges(stage.Width, stage.Height);
walls.add(new Wall(stage.Width/2, stage.Height/2, 20, stage.Height*2/3, -1));
walls.add(new Wall(stage.Width*3/4, stage.Height/2, stage.Width/2, 20, 1));
break;
case 3:
stage.Width = 800;
stage.Height = 600;
player = new Player(stage.Width/4, stage.Height/2);
enemies.add(new Enemy(stage.Width*2/3, stage.Height/4));
enemies.add(new Enemy(stage.Width*5/6, stage.Height/4));
enemies.add(new Trio(stage.Width*2/3, stage.Height*3/4));
edges(stage.Width, stage.Height);
walls.add(new Wall(stage.Width/2, stage.Height/2, 20, stage.Height*2/3, -1));
walls.add(new Wall(stage.Width*3/4, stage.Height/2, stage.Width/2, 20, 1));
break;
case 4:
stage.Width = 800;
stage.Height = 600;
player = new Player(stage.Width/2, stage.Height/2);
enemies.add(new Enemy(stage.Width/8, stage.Height/4));
enemies.add(new Enemy(stage.Width/8, stage.Height*3/4));
enemies.add(new Enemy(stage.Width*7/8, stage.Height/4));
enemies.add(new Enemy(stage.Width*7/8, stage.Height*3/4));
edges(stage.Width, stage.Height);
walls.add(new Wall(stage.Width/4, stage.Height/2, 20, stage.Height*3/4, 1));
walls.add(new Wall(stage.Width*3/4, stage.Height/2, 20, stage.Height*3/4, 1));
walls.add(new Wall(stage.Width/8, stage.Height/2, stage.Width/4, 20, 1));
walls.add(new Wall(stage.Width*7/8, stage.Height/2, stage.Width/4, 20, 1));
break;
case 5:
stage.Width = 800;
stage.Height = 600;
player = new Player(stage.Width/2, stage.Height/2);
enemies.add(new Enemy(stage.Width/8, stage.Height/4));
enemies.add(new Trio(stage.Width/8, stage.Height*3/4));
enemies.add(new Trio(stage.Width*7/8, stage.Height/4));
enemies.add(new Enemy(stage.Width*7/8, stage.Height*3/4));
enemies.add(new Enemy(stage.Width/2, stage.Height*7/8));
edges(stage.Width, stage.Height);
walls.add(new Wall(stage.Width/4, stage.Height/2, 20, stage.Height*3/4, 1));
walls.add(new Wall(stage.Width*3/4, stage.Height/2, 20, stage.Height*3/4, -1));
walls.add(new Wall(stage.Width/8, stage.Height/2, stage.Width/4, 20, 2));
walls.add(new Wall(stage.Width*7/8, stage.Height/2, stage.Width/4, 20, 1));
walls.add(new Wall(stage.Width/2, stage.Height/4, stage.Width/4, 50, 2));
walls.add(new Wall(stage.Width/2, stage.Height*3/4, stage.Width/4, 50, 1));
break;
case 6:
stage.Width = 800;
stage.Height = 600;
player = new Player(stage.Width/8, stage.Height/2);
enemies.add(new Mother(stage.Width/2, stage.Height/2));
enemies.add(new Trio(stage.Width*3/4, stage.Height/2));
enemies.add(new Enemy(stage.Width*3/4, stage.Height/10));
enemies.add(new Enemy(stage.Width*3/4, stage.Height*9/10));
edges(stage.Width, stage.Height);
walls.add( new Wall(stage.Width/4, stage.Height/2, 20, stage.Height/2 + 20, 1));
walls.add( new Wall(stage.Width/2, stage.Height/4, stage.Width/2 + 20, 20, 1));
walls.add( new Wall(stage.Width/2, stage.Height*3/4, stage.Width/2 + 20, 20, 1));
break;
case 7:
stage.Width = 800;
stage.Height = 600;
player = new Player(stage.Width/8, stage.Height/2);
enemies.add(new Trio(stage.Width/2, stage.Height/2));
enemies.add(new SlowEnemy(stage.Width*3/4, stage.Height/2));
enemies.add(new SlowEnemy(stage.Width*3/4, stage.Height/10));
enemies.add(new SlowEnemy(stage.Width*3/4, stage.Height*9/10));
edges(stage.Width, stage.Height);
walls.add( new Wall(stage.Width/4, stage.Height/2, 20, stage.Height/2 + 20, 1));
walls.add( new Wall(stage.Width/2, stage.Height/4, stage.Width/2 + 20, 20, 1));
walls.add( new Wall(stage.Width/2, stage.Height*3/4, stage.Width/2 + 20, 20, 1));
break;
default:
stage.level = 0;
loadWalls(0);
break;
}
}
实验效果截图
实验感悟
平时偶尔会看一些游戏区的主播进行游戏直播,其中一些看似画面简单但难度却爆炸的小游戏给我留下了很深刻的印象,于是便打算仿照制作一款类似的通关类的动作小游戏。
贪吃方块游戏参考了 代码本色 中的相关动画技术,其中包括第一章的向量,第四章的粒子,以及第五章的碰撞事件。在游戏关卡方面我只制作了七道关卡,但自己连第五关都过不了,这还是在我把前几关设置的比较容易的基础上,实在汗颜,或许我就是个手残党。