From 11d12e3d651cba93b6bd5d1757d9a916f00c5644 Mon Sep 17 00:00:00 2001 From: Mottributo <87079566+Mottributo@users.noreply.github.com> Date: Sun, 26 Mar 2023 16:58:15 +0300 Subject: [PATCH] Platforms correct visualization; opt-in shadow etc --- sketch.js | 372 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 242 insertions(+), 130 deletions(-) diff --git a/sketch.js b/sketch.js index 9be94e0..3ddc4d5 100644 --- a/sketch.js +++ b/sketch.js @@ -6,6 +6,7 @@ var fps_recent_values = []; var death_timer; var showDebugData = false; var debug_charTrace = []; +var shadows_enabled = false; var gameChar; @@ -26,40 +27,58 @@ function Platform(curGroundIndex, x, width, y) { this.curGroundIndex = curGroundIndex; this.x = x; this.width = width; - this.y = y || Math.pow(gameChar.baseJumpingStrength, 2) / 2 - 2 * gameChar.baseJumpingStrength; - - this.draw = function () { - push(); - stroke(0); - strokeWeight(2); - fill(palette.ground_color0); - rect( - this.x - this.width, - floorPos_y - this.y, - width*2, height/100, - ); + // 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; - pop(); + this.draw = function () { + push(); + stroke(0); + strokeWeight(2); + fill(palette.ground_colors[curGroundIndex]); + rect( + this.x - this.width, + this.y + 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(); + }; + this._isWithinX = function (who) { - if (who.x > this.x - this.width && who.x < this.x + this.width) { - return true; - } + if (who.x > this.x - this.width && who.x < this.x + this.width) { + return true; + } }; - + this.isBelow = function (who) { - if (this._isWithinX(who) && who.y > this.y) { - return true; - } + if (this._isWithinX(who) && who.y > this.y) { + return true; + } }; - + this.isAbove = function (who) { - if (this._isWithinX(who) && who.y < this.y) { - return true; - } + if (this._isWithinX(who) && who.y < this.y) { + return true; + } }; - } +} var text_size; // Variables to set colors. Set in setup() @@ -71,9 +90,11 @@ function setup() { body_color: color("white"), head_color: color("darkgreen"), sky_color: color("#8E9887"), - ground_color0: color("#684622"), - ground_color1: color("#734E26"), - ground_color2: color("#7F562A"), + ground_colors: [ + color("#874321"), + color("#636721"), + color("#634345") + ], river_river_color: color("#56C525"), river_river_wave_color: color("#4BAD21"), river_color: color("#7B672A"), @@ -128,7 +149,7 @@ function startGame(level_start) { speed: 5, baseLives: 3, curLives: 3, - baseJumpingStrength: 15, + baseJumpingStrength: 16, curJumpingStrength: 0, isRight: false, isLeft: false, @@ -136,24 +157,25 @@ function startGame(level_start) { isJumping: false, isPlummeting: false, curGroundIndex: 0, - - _updateSprite: function() - { - 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; - } - }, - + + _updateSprite: function () { + 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; + } + }, + draw: function () { this._updateSprite(); push(); @@ -325,6 +347,69 @@ function startGame(level_start) { this.y_step /= this.scale; 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 () { 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, platforms, enemies. @@ -446,8 +531,49 @@ function startGame(level_start) { } for (i = 0; i < 100; i++) { if (i == 0) { - platforms[0][0] = new Platform(0, 700, 50, - pow(gameChar.baseJumpingStrength, 2) / 2 - 2*gameChar.baseJumpingStrength); + platforms[0][0] = new Platform( + 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) + ) + ); } } } @@ -470,15 +596,19 @@ function draw() { // -------- GROUND ------------- drawGround(); - push(); + push(); fill(0); 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); + 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); + cameraPosX = lerp( + finish_position_x - width / 2, + cameraPosX, + camera_speed + ); // -------- CLOUDS -------------- drawClouds(); @@ -492,6 +622,11 @@ function draw() { } // -------- TREES --------------- drawTrees(); + // -------- PLATFORMS SHADOWS --- + if (shadows_enabled) + for (i=0; i= 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 + // GAMECHAR, PLATFORMS & ENEMIES RENDER + complexDraw(); + // - ------ GAME CHARACTER ------ + gameChar.act(); + pop(); // Scrolling end // -------- 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; i100) debug_charTrace.shift(); - push() - stroke(255,0,0); - strokeWeight(3); - translate(-cameraPosX, 0); - for (i=0;i 100) debug_charTrace.shift(); + push(); + stroke(255, 0, 0); + strokeWeight(3); + translate(-cameraPosX, 0); + for (i = 0; i < debug_charTrace.length; i++) { + point(debug_charTrace[i][0], debug_charTrace[i][1]); + } + translate(cameraPosX, 0); + pop(); } function checkRiver(t_river) { if ( @@ -601,16 +717,16 @@ function checkCollectable(t_collectable) { function drawGround() { push(); noStroke(); - fill(palette.ground_color0); + fill(palette.ground_colors[0]); rect(0, floorPos_y, width, height - floorPos_y); - fill(palette.ground_color1); + fill(palette.ground_colors[1]); rect( 0, floorPos_y + (2 * (height - floorPos_y)) / 6, width, floorPos_y + (2 * (height - floorPos_y)) / 6 ); - fill(palette.ground_color2); + fill(palette.ground_colors[2]); rect( 0, floorPos_y + (4 * (height - floorPos_y)) / 6, @@ -843,12 +959,19 @@ function drawTrees() { } } -function drawPlatforms() { - for (i=0; i 60) { - if (gameChar.curLives > 1) { - gameChar.curLives--; - death_timer = undefined; - startGame(); - } else if (gameChar.curLives == 1) { - gameChar.curLives--; - } else { - gameChar.curLives = 0; - } - } -} + function drawFps() { push(); fps = Math.round(frameRate() * 10) / 10; @@ -926,14 +1037,15 @@ function keyPressed() { startGame((level_start = true)); } } else if (!gameChar.isPlummeting) { - if (keyCode == 65 /*A*/ || keyCode == LEFT_ARROW) gameChar.isLeft = true; - if (keyCode == 68 /*D*/ || keyCode == RIGHT_ARROW) gameChar.isRight = true; + if (keyCode == 65 /*A*/ || keyCode == LEFT_ARROW) + gameChar.isLeft = true; + if (keyCode == 68 /*D*/ || keyCode == RIGHT_ARROW) + gameChar.isRight = true; if (keyCode == 83 /*S*/ || keyCode == DOWN_ARROW) gameChar.goDown(); 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 if ( - (keyCode == 32 /*Space*/ || - keyCode == 88 /*X*/) && + (keyCode == 32 /*Space*/ || keyCode == 88) /*X*/ && !gameChar.isFalling && !gameChar.isJumping ) {