1
\$\begingroup\$

I know this question sounds familiar but I'm working on a pretty big platformer (Written in PJS, on Khan Academy) and I don't want it to be just plain ground, I want slopes in the game (gentle slopes, steep, curvy, and smoothened) But I don't really know how to code it and the correct collision since I want it to feel like slopes in a sonic game where you can freely move but just going fast can make speeding through the level.

Here's a link to my project.

var slopeCollision = function(??){ return; }; var gravity = 2; // acceleration due to gravity in pixel/frame² var Slope = function(x, y, w, h) { this.x = x; this.y = y; this.w = w; // run this.h = h; // rise var mag = Math.hypot(w, h); var ux = w / mag; // unit run, aka cosine var uy = h / mag; // unit rise, aka sine var acc = uy * gravity; // scaler acceleration due to gravity this.ddx = ux * acc; // X axis acceleration due to gravity this.ddy = uy * acc; // Y axis acceleration due to gravity }; Slope.prototype.draw = function(cam) { var view = cam.view(this); if(view){ ellipse(view.x, view.y, 5, 5); line(view.x, view.y, view.x + view.w, view.y + view.h); ellipse(view.x + view.w, view.y + view.h, 2, 2); } }; /* * Apply this Slope's acceleration to obj. * Acceleration affects obj's velocity. * Obj's velocity affects its position. */ Slope.prototype.applyAcceleration = function(obj) { obj.dx += this.ddx; obj.x += obj.dx; obj.dy += this.ddy; obj.y += obj.dy; var gradient = 0.5; var yOffset = 0; for(var i = 0; i < circles.length; i++){ if(Collision(this, circles[i])){ circles[i].y = gradient * slope[0].x + yOffset; } } }; slope.add = function(x,y,w,h){ this.push(new Slope(x, y, w, h)); }; slope.apply = function(cam, circles){ for(var i = 0; i < this.length; i++){ this[i].draw(cam); this[i].applyAcceleration(circles); } }; 

Here's the images of the aforementioned slopes:

\$\endgroup\$
4
  • \$\begingroup\$ Is your level tile-based like Sonic games? If so, have you reviewed documentation describing how slopes were implemented in those games (e.g.on Sonic Retro)? Or investigated how they're implemented in open source clones like Open Sonic? \$\endgroup\$ Commented Aug 15, 2024 at 15:17
  • \$\begingroup\$ @DMGregory I did go to sonic retro and study that, I didn't make code of that but I do remember that every part of the slope changes the angle of sonic (or Bluey in this case) but its really the actual code for the slope, I'll put images of the types of slopes I mentioned but its really the code for it and the collision \$\endgroup\$ Commented Aug 15, 2024 at 16:12
  • \$\begingroup\$ @DMGregory Is there a JS open soure project cause the Open Sonic code needs to be opened on Windows or else my computer (Asus Chromebook) wouldn't run it but Is there anything else or code to use for slopes? \$\endgroup\$ Commented Aug 15, 2024 at 18:16
  • \$\begingroup\$ Thanks for your understanding related to the edit rollback. If you're in a hurry for an answer, have you tried searching through past Q&A threads about how to handle collisions with sloped tiles? \$\endgroup\$ Commented Aug 15, 2024 at 20:18

2 Answers 2

0
\$\begingroup\$

Use piecewise mathematical equations to build your level.

The slope is the derivative of the equation at that point.

In the case of discontinuities, average the previous and next values and recalculate(repeat as necessary).

\$\endgroup\$
5
  • 1
    \$\begingroup\$ This answer would be better if it demonstrated how to do that. \$\endgroup\$ Commented Aug 15, 2024 at 18:49
  • \$\begingroup\$ @DMGregory, true but providing direct answers to homework problems, or any "write this code for me", without attempt, should provide leading answers, not solutions. There is nothing in the question that expresses any effort from the OP. \$\endgroup\$ Commented Aug 15, 2024 at 18:59
  • \$\begingroup\$ @DMGregory, Personal opinions aside, There is not enough information in the question to give a concrete answer. \$\endgroup\$ Commented Aug 15, 2024 at 19:03
  • 1
    \$\begingroup\$ In cases like that, it's often helpful to post a clarifying comment and wait for more information before answering. \$\endgroup\$ Commented Aug 15, 2024 at 19:10
  • \$\begingroup\$ @DMGregory, The given code is boilerplate from an academic assignment, I should have flagged the question as low quality. No "clarifying comment" exists that could possibly resolve the issue. Hence my directed hint answer. Helpful but not overly so. \$\endgroup\$ Commented Aug 15, 2024 at 19:26
0
\$\begingroup\$

This is why I recommend using math to define your terrain, and match your graphics to suit (including by procedurally generating graphics). So...

A. Let's imagine you had a terrain consisting of a sine wave. At each point along the ground, your ground height would be the same as the wave height at that point:

t = xPosFrac = xPosScreen / screenWidth yPosTerrain = terrainAmplitude * Math.sin(2 * Math.PI * t) 

and your character will stand at a point on that sine wave:

yPosCharacter = yPosTerrain + characterHeight / 2 //...or without divide by 2, or + characterHeight (/2) depending on your screen coordinates system 

t is the fractional position between 0.0 and 1.0 along the horizontal length of that sine wave terrain, used to plot each point.

B. Let's imagine you had a terrain consisting of a straight line with a 1:2 slope / gradient (i.e. gradient == 0.5). Your ground height at each point would be:

yPos = gradient * x + yOffset //more formally, y = mx + c 

C. Let's imagine you wanted a mix of the aforementioned two functions to represent your terrain, i.e. a bumpy, uphill slope:

yPos = yPosFromSine / 2 + yPosFromLine / 2 

or of multiple functions:

yPos = (yPos1 + yPos2 + yPos3) / 3 

or more generally:

yPos = (yPos0...yPosN) / numFunctions 

Are you seeing the bigger picture? You can combine any number of mathematical functions this way, both to plot your terrain line, and then to position your character on that line.

You can also artificially weight the functions by multiplying each one by its own weightFactor, before adding them and dividing by numFunctions:

weights[0] = 0.4 weights[1] = 0.75 weights[2] = 1.0 funcs[0] = sineFunc; funcs[1] = lineFunc; funcs[2] = otherFunc; yPos = 0; for (let i = 0; i < funcs.length; i++) { yPos += funcs[i]() * weights[i]; } yPos /= funcs.length; //or divide by numFunctions 

If you decide to procedurally draw your graphics, you are basically going to plot a line from y==0, up to yPos for every xPos (screen pixel column). You can do whatever you like to make that look realistic, such as creating a colour gradient of black to green once you get to within say, 10 pixels of yPos, i.e. near the ground's surface. Make sense? Let me know if it needs clarification.

\$\endgroup\$
5
  • \$\begingroup\$ Finally got the math and updated the aformentioned program, only problem was that when Bluey (Player) collided it would take the player back or make him sorta clip, entering from the left puts you a few blocks back while going from the right clips him to the other end, Do I need to use a better collision system or am I missing something (I'm using your B: 1:2 slope method) @Engineer \$\endgroup\$ Commented Aug 17, 2024 at 3:18
  • \$\begingroup\$ @RomanStarCoder I think you'd need to at the very least share your lastest code in order for anyone here to make sense of what is happening. There is no reason why your character should not simply track the terrain surface, if you are only using my code above. If you are mixing code, it could be anything. \$\endgroup\$ Commented Aug 17, 2024 at 14:58
  • \$\begingroup\$ Updated the Post with latest code @Engineer \$\endgroup\$ Commented Aug 17, 2024 at 19:04
  • \$\begingroup\$ @RomanStarCoder Good that you posted the code but your explanation of what is going wrong is not clear. You could post a GIF or a video in your question. I've given what advice I can. You should be stepping through your code, line by line, in PJS as follows to understand exactly what it is doing and why you are having these problems, at the very moment they occur. Search for "Debugging with the Debugger" on that page. Good luck. \$\endgroup\$ Commented Aug 18, 2024 at 19:47
  • \$\begingroup\$ Video couldn't be uploaded for some reason but the link is still there, changing the line var scene = "nailThumb" to Play and reach a certain point in the level will show the slope and its collidable but it the same issue explained yesterday @Engineer \$\endgroup\$ Commented Aug 20, 2024 at 14:39

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.