Platforms correct visualization; opt-in shadow etc

This commit is contained in:
Mottributo 2023-03-26 16:58:15 +03:00
parent aa0943467f
commit 11d12e3d65

354
sketch.js
View File

@ -6,6 +6,7 @@ var fps_recent_values = [];
var death_timer; var death_timer;
var showDebugData = false; var showDebugData = false;
var debug_charTrace = []; var debug_charTrace = [];
var shadows_enabled = false;
var gameChar; var gameChar;
@ -26,40 +27,58 @@ function Platform(curGroundIndex, x, width, y) {
this.curGroundIndex = curGroundIndex; this.curGroundIndex = curGroundIndex;
this.x = x; this.x = x;
this.width = width; this.width = width;
this.y = y || Math.pow(gameChar.baseJumpingStrength, 2) / 2 - 2 * gameChar.baseJumpingStrength; // To make platforms jumpable to each other, define a max vertical difference
// thru an arithmetic progression dependent on the game character's jumping strength and gravity.
this.max_y_deviation =
(gameChar.baseJumpingStrength/gravity)*(gameChar.baseJumpingStrength)/2;
this.y = y || groundPositions[curGroundIndex] - this.max_y_deviation;
this.draw = function () { this.draw = function () {
push(); push();
stroke(0); stroke(0);
strokeWeight(2); strokeWeight(2);
fill(palette.ground_color0); fill(palette.ground_colors[curGroundIndex]);
rect( rect(
this.x - this.width, this.x - this.width,
floorPos_y - this.y, this.y + height / 100,
width*2, height/100, width * 2,
); height / 100
);
pop();
};
this.drawShadow = function () {
push();
// drawing shadow on the ground
noStroke();
fill("rgba(0,0,0, 0.15)");
rect(
this.x - this.width,
groundPositions[curGroundIndex],
width * 2,
height / 100
);
pop(); pop();
}; };
this._isWithinX = function (who) { this._isWithinX = function (who) {
if (who.x > this.x - this.width && who.x < this.x + this.width) { if (who.x > this.x - this.width && who.x < this.x + this.width) {
return true; return true;
} }
}; };
this.isBelow = function (who) { this.isBelow = function (who) {
if (this._isWithinX(who) && who.y > this.y) { if (this._isWithinX(who) && who.y > this.y) {
return true; return true;
} }
}; };
this.isAbove = function (who) { this.isAbove = function (who) {
if (this._isWithinX(who) && who.y < this.y) { if (this._isWithinX(who) && who.y < this.y) {
return true; return true;
} }
}; };
} }
var text_size; var text_size;
// Variables to set colors. Set in setup() // Variables to set colors. Set in setup()
@ -71,9 +90,11 @@ function setup() {
body_color: color("white"), body_color: color("white"),
head_color: color("darkgreen"), head_color: color("darkgreen"),
sky_color: color("#8E9887"), sky_color: color("#8E9887"),
ground_color0: color("#684622"), ground_colors: [
ground_color1: color("#734E26"), color("#874321"),
ground_color2: color("#7F562A"), color("#636721"),
color("#634345")
],
river_river_color: color("#56C525"), river_river_color: color("#56C525"),
river_river_wave_color: color("#4BAD21"), river_river_wave_color: color("#4BAD21"),
river_color: color("#7B672A"), river_color: color("#7B672A"),
@ -128,7 +149,7 @@ function startGame(level_start) {
speed: 5, speed: 5,
baseLives: 3, baseLives: 3,
curLives: 3, curLives: 3,
baseJumpingStrength: 15, baseJumpingStrength: 16,
curJumpingStrength: 0, curJumpingStrength: 0,
isRight: false, isRight: false,
isLeft: false, isLeft: false,
@ -137,22 +158,23 @@ function startGame(level_start) {
isPlummeting: false, isPlummeting: false,
curGroundIndex: 0, curGroundIndex: 0,
_updateSprite: function() _updateSprite: function () {
{ if (gameChar.isPlummeting) {
if (gameChar.isPlummeting) { gameChar.sprite = 2;
gameChar.sprite = 2; } else if (gameChar.isFalling) {
} else if (gameChar.isFalling) { gameChar.sprite = 2;
gameChar.sprite = 2; if (gameChar.isLeft && !gameChar.isRight)
if (gameChar.isLeft && !gameChar.isRight) gameChar.sprite = 5; gameChar.sprite = 5;
else if (gameChar.isRight && !gameChar.isLeft) else if (gameChar.isRight && !gameChar.isLeft)
gameChar.sprite = 6; gameChar.sprite = 6;
} else { } else {
if (gameChar.isLeft && !gameChar.isRight) gameChar.sprite = 4; if (gameChar.isLeft && !gameChar.isRight)
else if (gameChar.isRight && !gameChar.isLeft) gameChar.sprite = 4;
gameChar.sprite = 3; else if (gameChar.isRight && !gameChar.isLeft)
else gameChar.sprite = 1; gameChar.sprite = 3;
} else gameChar.sprite = 1;
}, }
},
draw: function () { draw: function () {
this._updateSprite(); this._updateSprite();
@ -325,6 +347,69 @@ function startGame(level_start) {
this.y_step /= this.scale; this.y_step /= this.scale;
pop(); pop();
}, },
drawShadow: function () {
push();
noStroke();
this.x_step *= this.scale;
this.y_step *= this.scale;
fill('rgba(0,0,0,0.2)');
if (!gameChar.isPlumetting) shadow_y = groundPositions[gameChar.curGroundIndex];
else shadow_y = NaN;
ellipse(gameChar.x,
shadow_y,
gameChar.x_step*5,
gameChar.y_step*1.5);
this.x_step /= this.scale;
this.y_step /= this.scale;
pop();
},
_checkPlayerDie: function () {
if (frameCount - death_timer > 60) {
if (gameChar.curLives > 1) {
gameChar.curLives--;
death_timer = undefined;
startGame();
} else if (gameChar.curLives == 1) {
gameChar.curLives--;
} else {
gameChar.curLives = 0;
}
}
},
act: function () {
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.curJumpingStrength;
gameChar.curJumpingStrength -= gravity;
if (gameChar.curJumpingStrength <= 0) {
gameChar.isFalling = true;
gameChar.isJumping = false;
}
} else if (gameChar.isFalling) {
gameChar.y -= gameChar.curJumpingStrength;
gameChar.curJumpingStrength -= gravity;
if (gameChar.y >= gameChar.getCurGroundY()) {
gameChar.y = gameChar.getCurGroundY();
gameChar.isFalling = false;
}
} else {
}
}
this._checkPlayerDie();
// Doing plummeting
if (gameChar.isPlummeting) {
// using OR operator to set to frameCount in case death_timer is undefined,
// but not updating the death_timer again in case it is not undefined.
death_timer = death_timer || frameCount;
gameChar.y += 3;
}
},
getCurGroundY: function () { getCurGroundY: function () {
return groundPositions[this.curGroundIndex]; return groundPositions[this.curGroundIndex];
}, },
@ -348,7 +433,7 @@ function startGame(level_start) {
} }
}, },
}; };
cameraPosX = gameChar.x - width/2; cameraPosX = gameChar.x - width / 2;
// Creating trees, clouds, mountains, rivers, collectables. // Creating trees, clouds, mountains, rivers, collectables.
{ {
// Creating trees, clouds, mountains, rivers, collectables, platforms, enemies. // Creating trees, clouds, mountains, rivers, collectables, platforms, enemies.
@ -446,8 +531,49 @@ function startGame(level_start) {
} }
for (i = 0; i < 100; i++) { for (i = 0; i < 100; i++) {
if (i == 0) { if (i == 0) {
platforms[0][0] = new Platform(0, 700, 50, platforms[0][0] = new Platform(
pow(gameChar.baseJumpingStrength, 2) / 2 - 2*gameChar.baseJumpingStrength); 0,
700,
50,
groundPositions[0] - Platform.max_y_deviation
);
platforms[1][0] = new Platform(
1,
800,
50,
groundPositions[1] - Platform.max_y_deviation
);
platforms[2][0] = new Platform(
2,
900,
50,
groundPositions[2] - Platform.max_y_deviation
);
} else {
let groundPosIndex = floor(
random(0, groundPositions.length)
);
// array.slice(-1)[0] gets the last element of an array without removing it,
// contrary to array.pop().
prev = platforms[groundPosIndex].slice(-1)[0];
// stopping generation after the flagpole
if (prev.x + prev.width + 155 > finish_position_x) break;
platforms[groundPosIndex].push(
new Platform(
groundPosIndex,
prev.x +
random(
prev.width + 70,
prev.width + 155
),
random(15, 60),
max(
random(prev.y -
prev.max_y_deviation,
floorPos_y - prev.max_y_deviation),
height / 8)
)
);
} }
} }
} }
@ -476,9 +602,13 @@ function draw() {
translate(-cameraPosX, 0); // Scrolling everything translate(-cameraPosX, 0); // Scrolling everything
// Focusing on the character. lerp() ensures fluid camera movement. // Focusing on the character. lerp() ensures fluid camera movement.
if (gameChar.x < finish_position_x) if (gameChar.x < finish_position_x)
cameraPosX = lerp(gameChar.x - width/2, cameraPosX, camera_speed); cameraPosX = lerp(gameChar.x - width / 2, cameraPosX, camera_speed);
else else
cameraPosX = lerp(finish_position_x - width/2, cameraPosX, camera_speed); cameraPosX = lerp(
finish_position_x - width / 2,
cameraPosX,
camera_speed
);
// -------- CLOUDS -------------- // -------- CLOUDS --------------
drawClouds(); drawClouds();
@ -492,6 +622,11 @@ function draw() {
} }
// -------- TREES --------------- // -------- TREES ---------------
drawTrees(); drawTrees();
// -------- PLATFORMS SHADOWS ---
if (shadows_enabled)
for (i=0; i<groundPositions.length; i++) {
drawPlatformsShadows(i);
}
// -------- COLLECTABLES -------- // -------- COLLECTABLES --------
for (i = 0; i < collectables.length; i++) { for (i = 0; i < collectables.length; i++) {
collectable = collectables[i]; collectable = collectables[i];
@ -501,49 +636,30 @@ function draw() {
// -------- FLAGPOLE ------------ // -------- FLAGPOLE ------------
renderFlagpole(); renderFlagpole();
if (!flagpole.isReached) checkFlagpole(); if (!flagpole.isReached) checkFlagpole();
// -------- PLATFORMS // GAMECHAR, PLATFORMS & ENEMIES RENDER
drawPlatforms(); complexDraw();
// - ------ GAME CHARACTER ------
// -------- GAME CHARACTER ------ gameChar.act();
{ pop(); // Scrolling end
// 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.curJumpingStrength;
gameChar.curJumpingStrength -= gravity;
if (gameChar.curJumpingStrength <= 0) {
gameChar.isFalling = true;
gameChar.isJumping = false;
}
} else if (gameChar.isFalling) {
gameChar.y -= gameChar.curJumpingStrength;
gameChar.curJumpingStrength -= gravity;
if (gameChar.y >= gameChar.getCurGroundY()) {
gameChar.y = gameChar.getCurGroundY();
gameChar.isFalling = false;
}
} else {
}
}
checkPlayerDie();
// Doing plummeting
if (gameChar.isPlummeting) {
if (death_timer == undefined) death_timer = frameCount;
gameChar.y += 3;
}
// Drawing a sprite
gameChar.draw();
}
pop(); // Scrolling
// -------- INTERFACE ----------- // -------- INTERFACE -----------
drawInterface();
}
function complexDraw() {
// Since platforms require being drawn in three different ordrs relative to enemies and the game character,
// a function is made to handle this and to decrease clutter.
for (i=0; i<=gameChar.curGroundIndex; i++) {
drawPlatforms(i);
}
if (shadows_enabled) gameChar.drawShadow();
gameChar.draw();
for (i=gameChar.curGroundIndex+1; i<groundPositions.length; i++) {
drawPlatforms(i);
}
}
function drawInterface() {
push(); push();
fill(0); fill(0);
stroke(0);
text("Score: " + game_score, 12, text_size); text("Score: " + game_score, 12, text_size);
drawLives(); drawLives();
if (gameChar.curLives < 1) if (gameChar.curLives < 1)
@ -563,16 +679,16 @@ function draw() {
} }
function drawCharTrace() { function drawCharTrace() {
debug_charTrace.push([gameChar.x, gameChar.y]); debug_charTrace.push([gameChar.x, gameChar.y]);
if (debug_charTrace.length>100) debug_charTrace.shift(); if (debug_charTrace.length > 100) debug_charTrace.shift();
push() push();
stroke(255,0,0); stroke(255, 0, 0);
strokeWeight(3); strokeWeight(3);
translate(-cameraPosX, 0); translate(-cameraPosX, 0);
for (i=0;i<debug_charTrace.length;i++) { for (i = 0; i < debug_charTrace.length; i++) {
point(debug_charTrace[i][0], debug_charTrace[i][1]); point(debug_charTrace[i][0], debug_charTrace[i][1]);
} }
translate(cameraPosX, 0); translate(cameraPosX, 0);
pop(); pop();
} }
function checkRiver(t_river) { function checkRiver(t_river) {
if ( if (
@ -601,16 +717,16 @@ function checkCollectable(t_collectable) {
function drawGround() { function drawGround() {
push(); push();
noStroke(); noStroke();
fill(palette.ground_color0); fill(palette.ground_colors[0]);
rect(0, floorPos_y, width, height - floorPos_y); rect(0, floorPos_y, width, height - floorPos_y);
fill(palette.ground_color1); fill(palette.ground_colors[1]);
rect( rect(
0, 0,
floorPos_y + (2 * (height - floorPos_y)) / 6, floorPos_y + (2 * (height - floorPos_y)) / 6,
width, width,
floorPos_y + (2 * (height - floorPos_y)) / 6 floorPos_y + (2 * (height - floorPos_y)) / 6
); );
fill(palette.ground_color2); fill(palette.ground_colors[2]);
rect( rect(
0, 0,
floorPos_y + (4 * (height - floorPos_y)) / 6, floorPos_y + (4 * (height - floorPos_y)) / 6,
@ -843,12 +959,19 @@ function drawTrees() {
} }
} }
function drawPlatforms() { function drawPlatforms(rowIndex) {
for (i=0; i<groundPositions.length; i++) { push();
for (k=0; k<platforms[i].length;k++) { for (k = 0; k < platforms[rowIndex].length; k++) {
platforms[i][k].draw(); platforms[rowIndex][k].draw();
} }
} pop();
}
function drawPlatformsShadows(rowIndex) {
push();
for (k = 0; k < platforms[rowIndex].length; k++) {
platforms[rowIndex][k].drawShadow();
}
pop();
} }
function renderFlagpole() { function renderFlagpole() {
@ -889,19 +1012,7 @@ function checkFlagpole() {
flagpole.isReached = true; flagpole.isReached = true;
} }
} }
function checkPlayerDie() {
if (frameCount - death_timer > 60) {
if (gameChar.curLives > 1) {
gameChar.curLives--;
death_timer = undefined;
startGame();
} else if (gameChar.curLives == 1) {
gameChar.curLives--;
} else {
gameChar.curLives = 0;
}
}
}
function drawFps() { function drawFps() {
push(); push();
fps = Math.round(frameRate() * 10) / 10; fps = Math.round(frameRate() * 10) / 10;
@ -926,14 +1037,15 @@ function keyPressed() {
startGame((level_start = true)); startGame((level_start = true));
} }
} else if (!gameChar.isPlummeting) { } else if (!gameChar.isPlummeting) {
if (keyCode == 65 /*A*/ || keyCode == LEFT_ARROW) gameChar.isLeft = true; if (keyCode == 65 /*A*/ || keyCode == LEFT_ARROW)
if (keyCode == 68 /*D*/ || keyCode == RIGHT_ARROW) gameChar.isRight = true; gameChar.isLeft = true;
if (keyCode == 68 /*D*/ || keyCode == RIGHT_ARROW)
gameChar.isRight = true;
if (keyCode == 83 /*S*/ || keyCode == DOWN_ARROW) gameChar.goDown(); if (keyCode == 83 /*S*/ || keyCode == DOWN_ARROW) gameChar.goDown();
if (keyCode == 87 /*W*/ || keyCode == UP_ARROW) gameChar.goUp(); if (keyCode == 87 /*W*/ || keyCode == UP_ARROW) gameChar.goUp();
// Rewrote jumping routine to make it more natural and be able to support platforms and different player dimensions // Rewrote jumping routine to make it more natural and be able to support platforms and different player dimensions
if ( if (
(keyCode == 32 /*Space*/ || (keyCode == 32 /*Space*/ || keyCode == 88) /*X*/ &&
keyCode == 88 /*X*/) &&
!gameChar.isFalling && !gameChar.isFalling &&
!gameChar.isJumping !gameChar.isJumping
) { ) {