2023-03-22 21:06:30 +00:00
|
|
|
var floorPos_y;
|
|
|
|
var cameraPosX;
|
2023-03-25 19:39:36 +00:00
|
|
|
var camera_speed;
|
2023-03-22 21:06:30 +00:00
|
|
|
var processStop_timer;
|
2023-03-23 14:21:02 +00:00
|
|
|
var fps_recent_values = [];
|
|
|
|
var showDebugData = false;
|
2023-03-22 21:06:30 +00:00
|
|
|
|
|
|
|
var gameChar;
|
|
|
|
|
|
|
|
var gravity;
|
|
|
|
var game_score;
|
|
|
|
var finish_position_x;
|
|
|
|
|
|
|
|
var trees_x = [];
|
|
|
|
var clouds = [];
|
|
|
|
var mountains = [];
|
|
|
|
var collectables = [];
|
2023-03-25 19:46:39 +00:00
|
|
|
var rivers = [];
|
2023-03-22 21:06:30 +00:00
|
|
|
var flagpole;
|
|
|
|
|
|
|
|
var text_size;
|
|
|
|
// Variables to set colors. Set in setup()
|
|
|
|
var palette;
|
|
|
|
|
|
|
|
function setup() {
|
|
|
|
createCanvas(1024, 576);
|
|
|
|
palette = {
|
|
|
|
body_color: color("white"),
|
|
|
|
head_color: color("darkgreen"),
|
|
|
|
sky_color: color("#8E9887"),
|
|
|
|
ground_color0: color("#684622"),
|
|
|
|
ground_color1: color("#734E26"),
|
|
|
|
ground_color2: color("#7F562A"),
|
2023-03-25 19:46:39 +00:00
|
|
|
river_river_color: color("#56C525"),
|
|
|
|
river_river_wave_color: color("#4BAD21"),
|
|
|
|
river_color: color("#7B672A"),
|
2023-03-22 21:06:30 +00:00
|
|
|
pine_leaves_color: color("#3F4834"),
|
|
|
|
maple_leaves_color: color("#4E3D1F"),
|
|
|
|
pine_stem: color("#644D0D"),
|
|
|
|
maple_stem: color("#936907"),
|
|
|
|
mountain: color("#5a5a5a"),
|
|
|
|
mountain_shadow: color("#3c3c3c"),
|
|
|
|
cloud0: color(200),
|
|
|
|
cloud1: color(220),
|
|
|
|
cloud2: color(255),
|
|
|
|
coin_outer: color("#FDC334"),
|
|
|
|
coin_middle: color("#ababab"),
|
|
|
|
coin_inner: color("#FDC334"),
|
|
|
|
heart_color: color("darkred"),
|
|
|
|
enemy_head_color: color("red"),
|
|
|
|
enemy_body_color: color("red"),
|
|
|
|
};
|
2023-03-25 18:52:09 +00:00
|
|
|
startGame((level_start = true));
|
2023-03-22 21:06:30 +00:00
|
|
|
}
|
2023-03-25 17:41:54 +00:00
|
|
|
function startGame(level_start) {
|
2023-03-22 21:06:30 +00:00
|
|
|
floorPos_y = 432;
|
2023-03-25 17:41:54 +00:00
|
|
|
// levels of depth where the character, collectable and enemies stand.
|
2023-03-25 17:33:19 +00:00
|
|
|
groundPositions = [
|
|
|
|
floorPos_y + (height - floorPos_y) / 6,
|
|
|
|
floorPos_y + (3 * (height - floorPos_y)) / 6,
|
|
|
|
floorPos_y + (5 * (height - floorPos_y)) / 6,
|
|
|
|
];
|
2023-03-25 19:39:36 +00:00
|
|
|
camera_speed = 0.9;
|
2023-03-25 17:41:54 +00:00
|
|
|
gravity = 1;
|
|
|
|
game_score = 0;
|
|
|
|
finish_position_x = 2000;
|
|
|
|
textSize(width / 20);
|
|
|
|
flagpole = {
|
|
|
|
x: finish_position_x,
|
|
|
|
isReached: false,
|
|
|
|
size_vert: 4,
|
|
|
|
size_hor: 7,
|
|
|
|
cell_size: 20,
|
|
|
|
cell_size_v: 20,
|
|
|
|
cell_size_h: 20,
|
|
|
|
};
|
|
|
|
if (level_start) {
|
2023-03-22 21:06:30 +00:00
|
|
|
gameChar = {
|
|
|
|
x: width / 2,
|
|
|
|
y: floorPos_y + (height - floorPos_y) / 6,
|
|
|
|
x_step: 5,
|
|
|
|
y_step: 8,
|
|
|
|
scale: 1,
|
|
|
|
sprite: 1,
|
|
|
|
speed: 5,
|
|
|
|
baseLives: 3,
|
|
|
|
curLives: 3,
|
|
|
|
isRight: false,
|
|
|
|
isLeft: false,
|
|
|
|
isFalling: false,
|
|
|
|
isJumping: false,
|
|
|
|
isPlummeting: false,
|
2023-03-25 17:33:19 +00:00
|
|
|
curGroundIndex: 0,
|
2023-03-22 21:06:30 +00:00
|
|
|
|
2023-03-23 19:33:39 +00:00
|
|
|
draw: function () {
|
2023-03-23 19:11:54 +00:00
|
|
|
push();
|
|
|
|
strokeWeight(1);
|
|
|
|
stroke(1);
|
2023-03-23 19:21:57 +00:00
|
|
|
this.x_step *= this.scale;
|
|
|
|
this.y_step *= this.scale;
|
2023-03-23 19:11:54 +00:00
|
|
|
function _drawBody(jumping = false) {
|
|
|
|
fill(palette.body_color);
|
|
|
|
if (jumping) {
|
|
|
|
triangle(
|
|
|
|
gameChar.x - gameChar.x_step * 2,
|
|
|
|
gameChar.y - gameChar.y_step * 1.5,
|
|
|
|
gameChar.x,
|
|
|
|
gameChar.y - gameChar.y_step * 4,
|
|
|
|
gameChar.x + gameChar.x_step * 2,
|
|
|
|
gameChar.y - gameChar.y_step * 1.5
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
triangle(
|
|
|
|
gameChar.x - gameChar.x_step * 2,
|
|
|
|
gameChar.y,
|
|
|
|
gameChar.x,
|
|
|
|
gameChar.y - gameChar.y_step * 4,
|
|
|
|
gameChar.x + gameChar.x_step * 2,
|
|
|
|
gameChar.y
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function _drawHead() {
|
|
|
|
fill(palette.head_color);
|
|
|
|
ellipse(
|
|
|
|
gameChar.x,
|
|
|
|
gameChar.y - gameChar.y_step * 5,
|
|
|
|
gameChar.x_step * 6,
|
|
|
|
gameChar.y_step * 4
|
|
|
|
);
|
|
|
|
}
|
|
|
|
function _drawEyes(draw_left, draw_right, eyes_height) {
|
|
|
|
fill(0);
|
|
|
|
if (draw_left) {
|
|
|
|
ellipse(
|
|
|
|
gameChar.x - gameChar.x_step * 1.2,
|
|
|
|
gameChar.y - gameChar.y_step * eyes_height,
|
|
|
|
gameChar.x_step / 1.5,
|
|
|
|
gameChar.y_step / 2
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (draw_right) {
|
|
|
|
ellipse(
|
|
|
|
gameChar.x + gameChar.x_step * 1.2,
|
|
|
|
gameChar.y - gameChar.y_step * eyes_height,
|
|
|
|
gameChar.x_step / 1.5,
|
|
|
|
gameChar.y_step / 2
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Standing, facing frontwards
|
2023-03-23 19:21:57 +00:00
|
|
|
if (this.sprite == 1) {
|
2023-03-23 19:11:54 +00:00
|
|
|
// Body
|
|
|
|
_drawBody();
|
|
|
|
// Head
|
|
|
|
_drawHead();
|
|
|
|
// Eyes
|
|
|
|
_drawEyes(true, true, 4.2);
|
|
|
|
}
|
|
|
|
// Jumping, facing forwards
|
|
|
|
else if (gameChar.sprite == 2) {
|
|
|
|
// Body
|
|
|
|
_drawBody(true);
|
|
|
|
// Hands. (Hands!)
|
|
|
|
line(
|
2023-03-23 19:21:57 +00:00
|
|
|
this.x - this.x_step * 1,
|
|
|
|
this.y - this.y_step * 2.5,
|
|
|
|
this.x - this.x_step * 3.2,
|
|
|
|
this.y - this.y_step * 3.2
|
2023-03-23 19:11:54 +00:00
|
|
|
);
|
|
|
|
line(
|
2023-03-23 19:21:57 +00:00
|
|
|
this.x + this.x_step * 1,
|
|
|
|
this.y - this.y_step * 2.5,
|
|
|
|
this.x + this.x_step * 3.2,
|
|
|
|
this.y - this.y_step * 3.2
|
2023-03-23 19:11:54 +00:00
|
|
|
);
|
|
|
|
// Head
|
|
|
|
_drawHead();
|
|
|
|
// Eyes
|
|
|
|
_drawEyes(true, true, 3.8);
|
|
|
|
}
|
|
|
|
// Walking right
|
2023-03-23 19:21:57 +00:00
|
|
|
else if (this.sprite == 3) {
|
2023-03-23 19:11:54 +00:00
|
|
|
// Body
|
|
|
|
_drawBody();
|
|
|
|
// Hand. (Hand!)
|
|
|
|
line(
|
2023-03-23 19:21:57 +00:00
|
|
|
this.x,
|
|
|
|
this.y - this.y_step * 2.5,
|
|
|
|
this.x + this.x_step * 0.8,
|
|
|
|
this.y - this.y_step * 1
|
2023-03-23 19:11:54 +00:00
|
|
|
);
|
|
|
|
// Head
|
|
|
|
_drawHead();
|
|
|
|
// Eyes
|
|
|
|
_drawEyes(false, true, 4.2);
|
|
|
|
}
|
|
|
|
// Walking left
|
2023-03-23 19:21:57 +00:00
|
|
|
else if (this.sprite == 4) {
|
2023-03-23 19:11:54 +00:00
|
|
|
// Body
|
|
|
|
_drawBody();
|
|
|
|
// Hand. (Hand!)
|
|
|
|
line(
|
2023-03-23 19:21:57 +00:00
|
|
|
this.x,
|
|
|
|
this.y - this.y_step * 2.5,
|
|
|
|
this.x - this.x_step * 0.8,
|
|
|
|
this.y - this.y_step * 1
|
2023-03-23 19:11:54 +00:00
|
|
|
);
|
|
|
|
// Head
|
|
|
|
_drawHead();
|
|
|
|
// Eyess
|
|
|
|
_drawEyes(true, false, 4.2);
|
|
|
|
}
|
|
|
|
// Jumping left
|
2023-03-23 19:21:57 +00:00
|
|
|
else if (this.sprite == 5) {
|
2023-03-23 19:11:54 +00:00
|
|
|
// Body
|
|
|
|
_drawBody(true);
|
|
|
|
// Hands. (Hands!)
|
|
|
|
line(
|
2023-03-23 19:21:57 +00:00
|
|
|
this.x - this.x_step * 1,
|
|
|
|
this.y - this.y_step * 2.5,
|
|
|
|
this.x - this.x_step * 3.2,
|
|
|
|
this.y - this.y_step * 3.2
|
2023-03-23 19:11:54 +00:00
|
|
|
);
|
|
|
|
line(
|
2023-03-23 19:21:57 +00:00
|
|
|
this.x + this.x_step * 1,
|
|
|
|
this.y - this.y_step * 2.5,
|
|
|
|
this.x + this.x_step * 3.2,
|
|
|
|
this.y - this.y_step * 3.2
|
2023-03-23 19:11:54 +00:00
|
|
|
);
|
|
|
|
// Head
|
|
|
|
_drawHead();
|
|
|
|
// Eyes
|
|
|
|
_drawEyes(true, false, 3.8);
|
|
|
|
}
|
|
|
|
// Jumping right
|
2023-03-23 19:21:57 +00:00
|
|
|
else if (this.sprite == 6) {
|
2023-03-23 19:11:54 +00:00
|
|
|
// Body
|
|
|
|
_drawBody(true);
|
|
|
|
// Hands. (Hands!)
|
|
|
|
line(
|
2023-03-23 19:21:57 +00:00
|
|
|
this.x - this.x_step * 1,
|
|
|
|
this.y - this.y_step * 2.5,
|
|
|
|
this.x - this.x_step * 3.2,
|
|
|
|
this.y - this.y_step * 3.2
|
2023-03-23 19:11:54 +00:00
|
|
|
);
|
|
|
|
line(
|
2023-03-23 19:21:57 +00:00
|
|
|
this.x + this.x_step * 1,
|
|
|
|
this.y - this.y_step * 2.5,
|
|
|
|
this.x + this.x_step * 3.2,
|
|
|
|
this.y - this.y_step * 3.2
|
2023-03-23 19:11:54 +00:00
|
|
|
);
|
|
|
|
// Head
|
|
|
|
_drawHead();
|
|
|
|
// Eyes
|
|
|
|
_drawEyes(false, true, 3.8);
|
|
|
|
} else {
|
|
|
|
text("Bad sprite number!", 10, 10);
|
2023-03-23 19:21:57 +00:00
|
|
|
console.error("Bad gameChar sprite number: " + this.sprite);
|
2023-03-23 19:11:54 +00:00
|
|
|
}
|
2023-03-23 19:21:57 +00:00
|
|
|
this.x_step /= this.scale;
|
|
|
|
this.y_step /= this.scale;
|
2023-03-23 19:11:54 +00:00
|
|
|
pop();
|
|
|
|
},
|
2023-03-25 17:33:19 +00:00
|
|
|
getCurGroundY: function () {
|
|
|
|
return groundPositions[this.curGroundIndex];
|
2023-03-22 21:06:30 +00:00
|
|
|
},
|
2023-03-23 19:33:39 +00:00
|
|
|
goUp: function () {
|
2023-03-25 17:33:19 +00:00
|
|
|
memorizedIndex = this.curGroundIndex;
|
|
|
|
this.curGroundIndex = max(0, this.curGroundIndex - 1);
|
|
|
|
if (memorizedIndex != this.curGroundIndex) {
|
2023-03-22 21:06:30 +00:00
|
|
|
gameChar.y -= (height - floorPos_y) / 3;
|
|
|
|
gameChar.scale -= 0.1;
|
|
|
|
}
|
|
|
|
},
|
2023-03-23 19:33:39 +00:00
|
|
|
goDown: function () {
|
2023-03-25 17:33:19 +00:00
|
|
|
memorizedIndex = this.curGroundIndex;
|
|
|
|
this.curGroundIndex = min(
|
|
|
|
groundPositions.length - 1,
|
|
|
|
this.curGroundIndex + 1
|
2023-03-22 21:06:30 +00:00
|
|
|
);
|
2023-03-25 17:33:19 +00:00
|
|
|
if (memorizedIndex != this.curGroundIndex) {
|
2023-03-22 21:06:30 +00:00
|
|
|
gameChar.y += (height - floorPos_y) / 3;
|
|
|
|
gameChar.scale += 0.1;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
};
|
2023-03-25 19:49:58 +00:00
|
|
|
cameraPosX = gameChar.x - width/2;
|
2023-03-25 19:46:39 +00:00
|
|
|
// Creating trees, clouds, mountains, rivers, collectables.
|
2023-03-25 17:41:54 +00:00
|
|
|
{
|
2023-03-25 19:46:39 +00:00
|
|
|
// Creating trees, clouds, mountains, rivers, collectables, platforms, enemies.
|
2023-03-25 17:41:54 +00:00
|
|
|
for (i = 0; i < 150; i++) {
|
|
|
|
trees_x[i] = random(-100, 10000);
|
|
|
|
}
|
|
|
|
for (i = 0; i < 100; i++) {
|
|
|
|
clouds[i] = {
|
|
|
|
x: random(-100, 10000),
|
|
|
|
y: random(0, floorPos_y / 2),
|
|
|
|
size: random(0.4, 2),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
// Latter mountains.
|
|
|
|
for (i = 0; i < finish_position_x / 90; i++) {
|
|
|
|
mountains[i] = {
|
|
|
|
x: random(-200, finish_position_x + 200),
|
|
|
|
width: random(60, 150),
|
|
|
|
height: random(floorPos_y - 50, floorPos_y - 150),
|
|
|
|
skew: random(-20, 20),
|
|
|
|
};
|
|
|
|
// To prevent spiky mountains which are quite ugly
|
2023-03-25 18:52:09 +00:00
|
|
|
mountains[i].height = max(
|
|
|
|
mountains[i].width,
|
|
|
|
mountains[i].height
|
|
|
|
);
|
2023-03-25 17:41:54 +00:00
|
|
|
}
|
|
|
|
// Start mountains.
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
|
|
mountains[i] = {
|
|
|
|
x: width / (i + 1.5),
|
|
|
|
width: width / (i + random(2, 4)),
|
|
|
|
height: height / (2 + 0.8 * i),
|
|
|
|
skew: (random(-10, 20) * i) / 2,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
for (i = 0; i < 100; i++) {
|
|
|
|
if (i == 0) {
|
2023-03-25 19:46:39 +00:00
|
|
|
rivers[0] = {
|
2023-03-25 17:41:54 +00:00
|
|
|
x: 700,
|
|
|
|
width: 50,
|
|
|
|
points: [],
|
|
|
|
};
|
|
|
|
} else {
|
2023-03-25 19:46:39 +00:00
|
|
|
if (rivers[i - 1].x + 600 > finish_position_x) break;
|
|
|
|
rivers[i] = {
|
|
|
|
x: rivers[i - 1].x + 300 + 200 * random(0.5, 1),
|
2023-03-25 17:41:54 +00:00
|
|
|
width: 50 + 30 * random(),
|
|
|
|
points: [],
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (i = 0; i < 100; i++) {
|
|
|
|
if (i == 0) {
|
|
|
|
collectables[0] = {
|
|
|
|
x: 600,
|
2023-03-25 18:52:09 +00:00
|
|
|
curGroundIndex: 0,
|
|
|
|
y:
|
|
|
|
groundPositions[0] -
|
|
|
|
10 /*taking 10 for better visuals*/,
|
2023-03-25 17:41:54 +00:00
|
|
|
size: 75,
|
|
|
|
isFound: false,
|
|
|
|
};
|
|
|
|
} else {
|
2023-03-25 18:52:09 +00:00
|
|
|
// Skipping generating coins after the finish line
|
2023-03-25 17:41:54 +00:00
|
|
|
if (collectables[i - 1].x + 200 > finish_position_x) {
|
|
|
|
break;
|
|
|
|
}
|
2023-03-25 18:52:09 +00:00
|
|
|
r = floor(random(0, groundPositions.length));
|
2023-03-25 17:41:54 +00:00
|
|
|
collectables[i] = {
|
|
|
|
x: collectables[i - 1].x + 50 + 100 * random(0.5, 1),
|
2023-03-25 18:52:09 +00:00
|
|
|
curGroundIndex: r,
|
|
|
|
y:
|
|
|
|
groundPositions[r] -
|
|
|
|
10 /*taking 10 for better visuals*/,
|
2023-03-25 17:41:54 +00:00
|
|
|
size: 75,
|
|
|
|
isFound: false,
|
|
|
|
};
|
2023-03-25 19:46:39 +00:00
|
|
|
// Checking whether the coin is over a river;
|
2023-03-25 17:41:54 +00:00
|
|
|
// marking it as isFound (making it disabled) in case if.
|
2023-03-25 19:46:39 +00:00
|
|
|
for (k = 0; k < rivers.length; k++) {
|
2023-03-25 17:41:54 +00:00
|
|
|
if (
|
2023-03-25 19:46:39 +00:00
|
|
|
rivers[k].x - rivers[k].width / 2 <
|
2023-03-25 17:41:54 +00:00
|
|
|
collectables[i].x &&
|
2023-03-25 19:46:39 +00:00
|
|
|
rivers[k].x + rivers[k].width / 2 >
|
2023-03-25 18:52:09 +00:00
|
|
|
collectables[i].x
|
2023-03-25 17:41:54 +00:00
|
|
|
) {
|
|
|
|
collectables[i].isFound = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-03-22 21:06:30 +00:00
|
|
|
} else {
|
|
|
|
gameChar.x = width / 2;
|
|
|
|
gameChar.y = floorPos_y + (height - floorPos_y) / 6;
|
|
|
|
gameChar.scale = 1;
|
2023-03-25 17:33:19 +00:00
|
|
|
gameChar.curGroundIndex = 0;
|
2023-03-22 21:06:30 +00:00
|
|
|
gameChar.isPlummeting = false;
|
|
|
|
gameChar.isFalling = false;
|
|
|
|
gameChar.isJumping = false;
|
|
|
|
gameChar.isLeft = false;
|
|
|
|
gameChar.isRight = false;
|
2023-03-25 18:52:09 +00:00
|
|
|
}
|
2023-03-22 21:06:30 +00:00
|
|
|
}
|
|
|
|
function draw() {
|
|
|
|
// -------- SKY ----------------
|
|
|
|
background(palette.sky_color);
|
|
|
|
|
|
|
|
// -------- GROUND -------------
|
|
|
|
drawGround();
|
|
|
|
|
2023-03-25 19:39:36 +00:00
|
|
|
push();
|
2023-03-22 21:06:30 +00:00
|
|
|
fill(0);
|
|
|
|
|
2023-03-25 19:39:36 +00:00
|
|
|
translate(-cameraPosX, 0); // Scrolling everything
|
|
|
|
// Focusing on the character. lerp() ensures fluid camera movement.
|
|
|
|
if (gameChar.x < finish_position_x)
|
|
|
|
cameraPosX = lerp(gameChar.x - width/2, cameraPosX, camera_speed);
|
|
|
|
else
|
|
|
|
cameraPosX = lerp(finish_position_x - width/2, cameraPosX, camera_speed);
|
2023-03-22 21:06:30 +00:00
|
|
|
|
|
|
|
// -------- CLOUDS --------------
|
|
|
|
drawClouds();
|
|
|
|
// -------- MOUNTAINS -----------
|
|
|
|
drawMountains();
|
|
|
|
// -------- CANYONS -------------
|
2023-03-25 19:46:39 +00:00
|
|
|
for (i = 0; i < rivers.length; i++) {
|
|
|
|
river = rivers[i];
|
|
|
|
drawRiver(river);
|
|
|
|
if (!gameChar.isFalling && !gameChar.isJumping) checkRiver(river);
|
2023-03-22 21:06:30 +00:00
|
|
|
}
|
|
|
|
// -------- TREES ---------------
|
|
|
|
drawTrees();
|
|
|
|
// -------- COLLECTABLES --------
|
|
|
|
for (i = 0; i < collectables.length; i++) {
|
|
|
|
collectable = collectables[i];
|
|
|
|
if (!collectable.isFound) drawCollectable(collectable);
|
|
|
|
checkCollectable(collectable);
|
|
|
|
}
|
|
|
|
// -------- FLAGPOLE ------------
|
|
|
|
renderFlagpole();
|
|
|
|
if (!flagpole.isReached) checkFlagpole();
|
|
|
|
|
|
|
|
// -------- GAME CHARACTER ------
|
|
|
|
{
|
|
|
|
// Behavior
|
|
|
|
if (!gameChar.isPlummeting) {
|
|
|
|
if (gameChar.isLeft && !gameChar.isRight) {
|
|
|
|
gameChar.x -= gameChar.speed;
|
|
|
|
} else if (gameChar.isRight && !gameChar.isLeft) {
|
|
|
|
gameChar.x += gameChar.speed;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gameChar.isJumping) {
|
|
|
|
gameChar.y -= gameChar.jumpingStrength;
|
|
|
|
gameChar.jumpingStrength -= gravity;
|
|
|
|
if (gameChar.jumpingStrength <= 0) {
|
|
|
|
gameChar.isFalling = true;
|
|
|
|
gameChar.isJumping = false;
|
|
|
|
}
|
|
|
|
} else if (gameChar.isFalling) {
|
|
|
|
gameChar.y -= gameChar.jumpingStrength;
|
|
|
|
gameChar.jumpingStrength -= gravity;
|
2023-03-25 17:33:19 +00:00
|
|
|
if (gameChar.y >= gameChar.getCurGroundY()) {
|
|
|
|
gameChar.y = gameChar.getCurGroundY();
|
2023-03-22 21:06:30 +00:00
|
|
|
gameChar.isFalling = false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
checkPlayerDie();
|
|
|
|
// Setting sprite
|
|
|
|
{
|
|
|
|
if (gameChar.isPlummeting) {
|
|
|
|
gameChar.sprite = 2;
|
|
|
|
} else if (gameChar.isFalling) {
|
|
|
|
gameChar.sprite = 2;
|
|
|
|
if (gameChar.isLeft && !gameChar.isRight) gameChar.sprite = 5;
|
|
|
|
else if (gameChar.isRight && !gameChar.isLeft)
|
|
|
|
gameChar.sprite = 6;
|
|
|
|
} else {
|
|
|
|
if (gameChar.isLeft && !gameChar.isRight) gameChar.sprite = 4;
|
|
|
|
else if (gameChar.isRight && !gameChar.isLeft)
|
|
|
|
gameChar.sprite = 3;
|
|
|
|
else gameChar.sprite = 1;
|
|
|
|
}
|
|
|
|
}
|
2023-03-25 19:49:58 +00:00
|
|
|
// Doing plummeting
|
2023-03-22 21:06:30 +00:00
|
|
|
if (gameChar.isPlummeting) {
|
|
|
|
gameChar.y += 3;
|
|
|
|
}
|
|
|
|
// Drawing a sprite
|
2023-03-23 19:11:54 +00:00
|
|
|
gameChar.draw();
|
2023-03-22 21:06:30 +00:00
|
|
|
}
|
|
|
|
pop(); // Scrolling
|
|
|
|
// -------- INTERFACE -----------
|
|
|
|
push();
|
|
|
|
fill(0);
|
|
|
|
text("Score: " + game_score, 12, text_size);
|
|
|
|
drawLives();
|
|
|
|
if (gameChar.curLives < 1)
|
|
|
|
text("Game over. Press space to continue...", 0, height / 2);
|
|
|
|
else if (flagpole.isReached)
|
|
|
|
text("Level complete. Press space to continue...", 0, height / 2);
|
2023-03-23 14:21:02 +00:00
|
|
|
if (showDebugData) {
|
2023-03-25 17:33:19 +00:00
|
|
|
text(gameChar.curGroundIndex, 99, 99);
|
2023-03-23 14:22:33 +00:00
|
|
|
text(gameChar.getCurGroundPosY(), 188, 99);
|
|
|
|
text(gameChar.sprite, 277, 99);
|
|
|
|
drawFps();
|
2023-03-23 14:21:02 +00:00
|
|
|
}
|
2023-03-22 21:06:30 +00:00
|
|
|
pop();
|
|
|
|
}
|
2023-03-25 19:46:39 +00:00
|
|
|
function checkRiver(t_river) {
|
2023-03-22 21:06:30 +00:00
|
|
|
if (
|
2023-03-25 19:46:39 +00:00
|
|
|
gameChar.x > river.x - river.width / 2 &&
|
|
|
|
gameChar.x < river.x + river.width / 2
|
2023-03-22 21:06:30 +00:00
|
|
|
) {
|
|
|
|
gameChar.isPlummeting = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function checkCollectable(t_collectable) {
|
|
|
|
if (
|
|
|
|
!t_collectable.isFound &&
|
2023-03-25 18:52:09 +00:00
|
|
|
collectable.curGroundIndex == gameChar.curGroundIndex &&
|
2023-03-22 21:06:30 +00:00
|
|
|
dist(
|
|
|
|
t_collectable.x,
|
2023-03-23 13:31:39 +00:00
|
|
|
t_collectable.y,
|
2023-03-22 21:06:30 +00:00
|
|
|
gameChar.x,
|
|
|
|
gameChar.y - gameChar.x_step * 4
|
|
|
|
) <
|
|
|
|
t_collectable.size / 2
|
|
|
|
) {
|
|
|
|
t_collectable.isFound = true;
|
|
|
|
game_score++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function drawGround() {
|
|
|
|
push();
|
|
|
|
noStroke();
|
|
|
|
fill(palette.ground_color0);
|
|
|
|
rect(0, floorPos_y, width, height - floorPos_y);
|
|
|
|
fill(palette.ground_color1);
|
|
|
|
rect(
|
|
|
|
0,
|
|
|
|
floorPos_y + (2 * (height - floorPos_y)) / 6,
|
|
|
|
width,
|
|
|
|
floorPos_y + (2 * (height - floorPos_y)) / 6
|
|
|
|
);
|
|
|
|
fill(palette.ground_color2);
|
|
|
|
rect(
|
|
|
|
0,
|
|
|
|
floorPos_y + (4 * (height - floorPos_y)) / 6,
|
|
|
|
width,
|
|
|
|
floorPos_y + (4 * (height - floorPos_y)) / 6
|
|
|
|
);
|
|
|
|
stroke(1);
|
|
|
|
translate(-cameraPosX, 0);
|
2023-03-23 19:33:39 +00:00
|
|
|
for (i = -width / 2; i < finish_position_x + width / 2; i += 20) {
|
2023-03-22 21:06:30 +00:00
|
|
|
line(
|
|
|
|
i,
|
|
|
|
floorPos_y + (2 * (height - floorPos_y)) / 6,
|
|
|
|
i + 1,
|
|
|
|
floorPos_y + (2 * (height - floorPos_y)) / 6
|
|
|
|
);
|
|
|
|
line(
|
|
|
|
i,
|
|
|
|
floorPos_y + (4 * (height - floorPos_y)) / 6,
|
|
|
|
i + 1,
|
|
|
|
floorPos_y + (4 * (height - floorPos_y)) / 6
|
|
|
|
);
|
|
|
|
}
|
|
|
|
pop();
|
|
|
|
}
|
2023-03-25 19:46:39 +00:00
|
|
|
function drawRiver(t_river) {
|
2023-03-22 21:06:30 +00:00
|
|
|
push();
|
2023-03-25 19:46:39 +00:00
|
|
|
fill(palette.river_river_color);
|
|
|
|
rect(t_river.x - t_river.width / 2, floorPos_y, t_river.width, height);
|
2023-03-23 12:49:47 +00:00
|
|
|
|
2023-03-23 13:31:39 +00:00
|
|
|
// Waves animation.
|
|
|
|
if (frameCount % 2 == 0) {
|
2023-03-22 21:06:30 +00:00
|
|
|
PointX = random(
|
2023-03-25 19:46:39 +00:00
|
|
|
t_river.x - t_river.width / 2 + 5,
|
|
|
|
t_river.x + t_river.width / 2 - 5
|
2023-03-22 21:06:30 +00:00
|
|
|
);
|
|
|
|
PointY = random(floorPos_y, height);
|
2023-03-25 19:46:39 +00:00
|
|
|
if (t_river.points.length > 2) {
|
|
|
|
t_river.points.shift();
|
2023-03-22 21:06:30 +00:00
|
|
|
}
|
2023-03-25 19:46:39 +00:00
|
|
|
t_river.points.push([PointX, PointY, random(20, 100)]);
|
2023-03-22 21:06:30 +00:00
|
|
|
}
|
2023-03-25 19:46:39 +00:00
|
|
|
stroke(palette.river_river_wave_color);
|
2023-03-22 21:06:30 +00:00
|
|
|
strokeWeight(5);
|
2023-03-25 19:46:39 +00:00
|
|
|
for (k = 0; k < t_river.points.length; k++) {
|
2023-03-23 12:49:47 +00:00
|
|
|
line(
|
2023-03-25 19:46:39 +00:00
|
|
|
t_river.points[k][0],
|
|
|
|
t_river.points[k][1],
|
|
|
|
t_river.points[k][0],
|
|
|
|
t_river.points[k][1] + t_river.points[k][2]
|
2023-03-23 12:49:47 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-03-22 21:06:30 +00:00
|
|
|
pop();
|
|
|
|
}
|
|
|
|
function drawCollectable(t_collectable) {
|
2023-03-23 13:31:39 +00:00
|
|
|
push();
|
2023-03-25 18:52:09 +00:00
|
|
|
// centering coins a bit upper
|
2023-03-23 13:31:39 +00:00
|
|
|
// animating the coin's jiggle
|
2023-03-25 18:52:09 +00:00
|
|
|
// a - vert. intensity, c - hor. intensity, b - vert. speed, d - hor. speed
|
2023-03-23 13:46:18 +00:00
|
|
|
a = 0.1;
|
|
|
|
b = 3;
|
|
|
|
c = 0.2;
|
2023-03-25 18:52:09 +00:00
|
|
|
d = 2;
|
2023-03-23 13:46:18 +00:00
|
|
|
t_collectable.y -= sin(frameCount * a) * b;
|
|
|
|
t_collectable.x += sin(frameCount * c) * d;
|
2023-03-22 21:06:30 +00:00
|
|
|
stroke(0.2);
|
|
|
|
fill(palette.coin_outer);
|
2023-03-23 13:31:39 +00:00
|
|
|
ellipse(t_collectable.x, t_collectable.y, 0.7 * t_collectable.size);
|
2023-03-22 21:06:30 +00:00
|
|
|
fill(palette.coin_middle);
|
2023-03-23 13:31:39 +00:00
|
|
|
ellipse(t_collectable.x, t_collectable.y, 0.6 * t_collectable.size);
|
2023-03-22 21:06:30 +00:00
|
|
|
fill(palette.coin_inner);
|
2023-03-23 13:31:39 +00:00
|
|
|
ellipse(t_collectable.x, t_collectable.y, 0.5 * t_collectable.size);
|
|
|
|
// restoring coin's coordinates to preserve game logic
|
2023-03-23 13:46:18 +00:00
|
|
|
t_collectable.y += sin(frameCount * a) * b;
|
|
|
|
t_collectable.x -= sin(frameCount * c) * d;
|
2023-03-23 13:31:39 +00:00
|
|
|
pop();
|
2023-03-22 21:06:30 +00:00
|
|
|
}
|
|
|
|
function drawClouds() {
|
|
|
|
for (i = 0; i < clouds.length; i++) {
|
|
|
|
push();
|
2023-03-25 18:52:09 +00:00
|
|
|
// imitating clouds movement, upper ones should go faster
|
|
|
|
translate((frameCount / clouds[i].y) * 20, 0);
|
2023-03-23 13:39:49 +00:00
|
|
|
// Adding counter-translating to implement parallax, the feeling of depth
|
2023-03-23 13:46:18 +00:00
|
|
|
translate(cameraPosX / 1.1, 0);
|
2023-03-23 14:22:33 +00:00
|
|
|
|
2023-03-22 21:06:30 +00:00
|
|
|
noStroke();
|
|
|
|
fill(palette.cloud0);
|
|
|
|
ellipse(
|
|
|
|
clouds[i].x - 20,
|
|
|
|
clouds[i].y - 10,
|
|
|
|
20 * clouds[i].size,
|
|
|
|
30 * clouds[i].size
|
|
|
|
);
|
|
|
|
fill(palette.cloud1);
|
|
|
|
ellipse(
|
|
|
|
clouds[i].x + 20,
|
|
|
|
clouds[i].y - 20,
|
|
|
|
70 * clouds[i].size,
|
|
|
|
50 * clouds[i].size
|
|
|
|
);
|
|
|
|
fill(palette.cloud2);
|
|
|
|
ellipse(
|
|
|
|
clouds[i].x,
|
|
|
|
clouds[i].y,
|
|
|
|
90 * clouds[i].size,
|
|
|
|
40 * clouds[i].size
|
|
|
|
);
|
|
|
|
ellipse(
|
|
|
|
clouds[i].x + 45,
|
|
|
|
clouds[i].y - 10,
|
|
|
|
50 * clouds[i].size,
|
|
|
|
35 * clouds[i].size
|
|
|
|
);
|
|
|
|
pop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function drawMountains() {
|
|
|
|
for (i = 0; i < mountains.length; i++) {
|
2023-03-23 13:35:28 +00:00
|
|
|
push();
|
|
|
|
// slowing down translation to add parallax, the feeling of depth
|
2023-03-23 14:21:02 +00:00
|
|
|
translate(cameraPosX / 2, 0);
|
2023-03-22 21:06:30 +00:00
|
|
|
noStroke();
|
|
|
|
fill(palette.mountain_shadow);
|
|
|
|
triangle(
|
|
|
|
mountains[i].x - mountains[i].width,
|
|
|
|
floorPos_y,
|
|
|
|
mountains[i].x + mountains[i].skew,
|
|
|
|
mountains[i].height,
|
|
|
|
mountains[i].x + mountains[i].width,
|
|
|
|
floorPos_y
|
|
|
|
);
|
|
|
|
fill(palette.mountain);
|
|
|
|
triangle(
|
|
|
|
mountains[i].x - mountains[i].width,
|
|
|
|
floorPos_y,
|
|
|
|
mountains[i].x + mountains[i].skew,
|
|
|
|
mountains[i].height,
|
|
|
|
mountains[i].x - mountains[i].width / 1.5,
|
|
|
|
floorPos_y
|
|
|
|
);
|
2023-03-23 13:35:28 +00:00
|
|
|
pop();
|
2023-03-22 21:06:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
function drawHeart(isEmpty, x, y, size) {
|
|
|
|
push();
|
|
|
|
if (isEmpty) {
|
|
|
|
noFill();
|
|
|
|
stroke(0);
|
|
|
|
} else {
|
|
|
|
fill(palette.heart_color);
|
|
|
|
stroke(palette.heart_color);
|
|
|
|
}
|
|
|
|
triangle(x, y, x + size, y - size, x + size * 2, y);
|
|
|
|
triangle(x - size * 2, y, x - size, y - size, x, y);
|
|
|
|
triangle(x, y, x + size, y + size, x - size, y + size);
|
|
|
|
triangle(x - size * 2, y, x, y + size * 2, x + size * 2, y);
|
|
|
|
pop();
|
|
|
|
}
|
|
|
|
function drawLives() {
|
|
|
|
push();
|
|
|
|
stroke(255, 0, 0);
|
|
|
|
noFill();
|
|
|
|
var heart_size = 20;
|
|
|
|
for (i = gameChar.baseLives; i > 0; i--) {
|
|
|
|
drawHeart(
|
|
|
|
true,
|
|
|
|
width - i * heart_size * 4.5,
|
|
|
|
heart_size * 1.5,
|
|
|
|
heart_size
|
|
|
|
);
|
|
|
|
}
|
|
|
|
for (i = gameChar.curLives; i > 0; i--) {
|
|
|
|
drawHeart(
|
|
|
|
false,
|
|
|
|
width - i * heart_size * 4.5,
|
|
|
|
heart_size * 1.5,
|
|
|
|
heart_size
|
|
|
|
);
|
|
|
|
}
|
|
|
|
pop();
|
|
|
|
}
|
|
|
|
function drawTrees() {
|
|
|
|
for (i = 0; i < trees_x.length; i++) {
|
|
|
|
// Draw pine in case the integer part of tree
|
|
|
|
// coordinate is even.
|
|
|
|
if (Math.trunc(trees_x[i]) % 2 == 0) {
|
|
|
|
fill(palette.pine_stem);
|
|
|
|
triangle(
|
|
|
|
trees_x[i] - 15,
|
|
|
|
floorPos_y,
|
|
|
|
trees_x[i],
|
|
|
|
floorPos_y - 150,
|
|
|
|
trees_x[i] + 15,
|
|
|
|
floorPos_y
|
|
|
|
);
|
|
|
|
fill(palette.pine_leaves_color);
|
|
|
|
triangle(
|
|
|
|
trees_x[i] - 45,
|
|
|
|
floorPos_y - 45,
|
|
|
|
trees_x[i],
|
|
|
|
floorPos_y - 120,
|
|
|
|
trees_x[i] + 45,
|
|
|
|
floorPos_y - 45
|
|
|
|
);
|
|
|
|
triangle(
|
|
|
|
trees_x[i] - 45,
|
|
|
|
floorPos_y - 85,
|
|
|
|
trees_x[i],
|
|
|
|
floorPos_y - 180,
|
|
|
|
trees_x[i] + 45,
|
|
|
|
floorPos_y - 85
|
|
|
|
);
|
|
|
|
}
|
|
|
|
// Draw maple
|
|
|
|
else {
|
|
|
|
fill(palette.maple_stem);
|
|
|
|
triangle(
|
|
|
|
trees_x[i] - 10,
|
|
|
|
floorPos_y,
|
|
|
|
trees_x[i],
|
|
|
|
floorPos_y - 120,
|
|
|
|
trees_x[i] + 10,
|
|
|
|
floorPos_y
|
|
|
|
);
|
|
|
|
fill(palette.maple_leaves_color);
|
|
|
|
ellipse(trees_x[i], floorPos_y - 50, 80, 30);
|
|
|
|
ellipse(trees_x[i], floorPos_y - 70, 100, 30);
|
|
|
|
ellipse(trees_x[i], floorPos_y - 90, 80, 30);
|
|
|
|
ellipse(trees_x[i], floorPos_y - 110, 40, 30);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function renderFlagpole() {
|
|
|
|
// NB - This function is implemented a bit differently than how it was requested in Part 6.
|
|
|
|
// It has no states to switch between - instead, the flag gradually goes into the opposite direction
|
|
|
|
// as the player crosses it, what is done by manipulating flagpole's parameters.
|
|
|
|
// This is done for animation purposes.
|
|
|
|
|
|
|
|
push();
|
|
|
|
strokeWeight(0);
|
|
|
|
fill(0);
|
|
|
|
|
|
|
|
// Movement animation, as mentioned in NB.
|
|
|
|
if (flagpole.isReached && flagpole.cell_size_h > -flagpole.cell_size)
|
|
|
|
flagpole.cell_size_h -= 0.8;
|
|
|
|
// the flagpole pole
|
|
|
|
rect(flagpole.x, floorPos_y / 2, 2, floorPos_y / 2);
|
|
|
|
|
|
|
|
// the flagpole flag
|
|
|
|
for (i = 0; i < flagpole.size_hor; i++) {
|
|
|
|
for (j = 0; j < flagpole.size_vert; j++) {
|
|
|
|
fill(((i + j) % 2) * 255);
|
|
|
|
rect(
|
|
|
|
flagpole.x + flagpole.cell_size_h * i,
|
|
|
|
floorPos_y / 2 + flagpole.cell_size_v * j,
|
|
|
|
flagpole.cell_size_h,
|
|
|
|
flagpole.cell_size_v
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pop();
|
|
|
|
}
|
|
|
|
function checkFlagpole() {
|
|
|
|
// Considering the linear nature of the game, the flagpole is triggered whenever player is beyond it by x.
|
|
|
|
// If to imagine a hypothetical jump where the player somehow jumps beyond the pole in one frame,
|
|
|
|
// this function will trigger anyway.
|
|
|
|
if (gameChar.x >= finish_position_x) {
|
|
|
|
flagpole.isReached = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function checkPlayerDie() {
|
|
|
|
if (gameChar.y >= height) {
|
|
|
|
if (gameChar.curLives > 1) {
|
|
|
|
gameChar.curLives--;
|
|
|
|
startGame();
|
|
|
|
} else if (gameChar.curLives == 1) {
|
|
|
|
gameChar.curLives--;
|
|
|
|
} else {
|
|
|
|
gameChar.curLives = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-03-23 14:21:02 +00:00
|
|
|
function drawFps() {
|
|
|
|
push();
|
2023-03-23 14:22:33 +00:00
|
|
|
fps = Math.round(frameRate() * 10) / 10;
|
|
|
|
if (fps_recent_values.length < 200) fps_recent_values.push(fps);
|
|
|
|
else fps_recent_values.shift();
|
|
|
|
fps_recent_values.push(fps);
|
2023-03-23 14:21:02 +00:00
|
|
|
fill("red");
|
|
|
|
text(fps, 400, 99);
|
|
|
|
stroke("black");
|
|
|
|
beginShape(LINES);
|
|
|
|
for (i = 1; i < fps_recent_values.length; i++) {
|
|
|
|
vertex(i, fps_recent_values[i]);
|
|
|
|
}
|
|
|
|
endShape();
|
|
|
|
pop();
|
|
|
|
}
|
2023-03-22 21:06:30 +00:00
|
|
|
function keyPressed() {
|
|
|
|
console.log(frameCount + " pressed " + key + " " + keyCode);
|
|
|
|
if (gameChar.curLives < 1 || flagpole.isReached) {
|
|
|
|
if (keyCode == 32 /*Space*/) {
|
|
|
|
/*Hard resets the game*/
|
2023-03-25 18:52:09 +00:00
|
|
|
startGame((level_start = true));
|
2023-03-22 21:06:30 +00:00
|
|
|
}
|
|
|
|
} else if (!gameChar.isPlummeting) {
|
|
|
|
if (keyCode == 65 /*A*/) gameChar.isLeft = true;
|
|
|
|
if (keyCode == 68 /*D*/) gameChar.isRight = true;
|
|
|
|
if (keyCode == 83 /*S*/) gameChar.goDown();
|
|
|
|
if (keyCode == 87 /*W*/) gameChar.goUp();
|
|
|
|
// Rewrote jumping routine to make it more natural and be able to support platforms and different player dimensions
|
|
|
|
if (
|
|
|
|
keyCode == 32 /*Space*/ &&
|
|
|
|
!gameChar.isFalling &&
|
|
|
|
!gameChar.isJumping
|
|
|
|
) {
|
|
|
|
gameChar.isJumping = true;
|
|
|
|
gameChar.jumpingStrength = 15;
|
|
|
|
}
|
|
|
|
}
|
2023-03-23 14:21:02 +00:00
|
|
|
if (keyCode == 77 /*M*/) showDebugData = !showDebugData;
|
2023-03-22 21:06:30 +00:00
|
|
|
}
|
|
|
|
function keyReleased() {
|
|
|
|
console.log(frameCount + " released " + key + " " + keyCode);
|
|
|
|
if (keyCode == 65 /*A*/) gameChar.isLeft = false;
|
|
|
|
if (keyCode == 68 /*D*/) gameChar.isRight = false;
|
2023-03-25 17:33:19 +00:00
|
|
|
}
|