MakeCode Kart

Have you seen @CDarius’s Outrun? Outrun

That approach does seem to be a better fit for the hardware. It’s not full 3D (you can’t have a camera view looking sideways across the road), but it allows for a lot of detail and is quite efficient.

2 Likes

I have a pipe sprite - I just need to know how to position it on-screen the best.
image
I tried many things (then deleted the blocks that I tried), but I just don’t have ideas on

  1. how to map pipes for easy placing throughout the stage
  2. how to place the pipes on the right position (and scale) on-screen

I was thinking tilemaps, but then they wouldn’t be super precise. I used the tilemap as a placeholder, but just couldn’t get the positioning right (I know it’s something to do with the angle from the player to the pipe and the viewing angle.)

I just need to know how to position it on-screen the best.

That’s what I meant earlier about needing object placement code. My example uses x/y coordinates to place the camera, they are pixel coordinates in the track image. (They can be fractional numbers, for example x=15.3 when the camera is in between x=15 and x=16.) The visible area of the scene is a frustum (a pyramid with the tip sliced off), it looks like a cut-off triangle in a top down view. See @AqeeAqee’s picture in this post, and imagine that being placed on top of the track texture.

If you want to place objects on the track, you need to transform from track coordinates to screen coordinates. That’s roughly a translation to put the origin at the current camera position, a rotation by -heading degrees, a perspective transform (roughly, dividing screen X and Y by the Z distance), and finally scaling/translation to get pixel coordinates. That needs some math to get right and to avoid “moonwalking” - you want objects to appear firmly attached to the ground. I’ll try to take a look at this when I find time, but that may take a while.

You guys should use @unsigned arduino’s gif to pixel converter for the character sprites and you just copy and paste the sprites in the array onto into animation blocks.but so far this is realy great I have no clue how you managed to do it tbf

Hello, again! It certainly has been a long time!

1 Like

@kwx I have made a separate collision map for mapping collision, offroad, and pipes that isn’t visible in-game, and I have made a way to easily place sprite positions, just by making a purple pixel in the collision map, and when the game starts up, it will look for all purple pixels and put their x/y positions into two separate arrays of x and y positions. Here’s the game, and I hope having a list of x/y positions ready for “processing” might be helpful for trying to code/debug it, since “all you have to do” is render the pipes based on the x/y positions in the arrays.

1 Like

I think I got object placement working with minimal moonwalking. Here’s a test showing sprites placed in 3D space, with Z ordering to ensure that overlapping objects get drawn correctly.

(The wireframe cubes are just a debugging aid to help visualize the geometry.)

I’ve also changed it so that the camera is placed behind the player car for third-person steering. The previous version was using a first-person cockpit view.

5 Likes

Can you make it the faster you go the less steerable it gets! (when slow you can take tight corners and go fast through long turns)
Also I got stuck somehow after some time (3rd lap or so) which happened multiple times

2 Likes

Great 3D effect and high perf !
Though it take me a while to understand how it work, but it’s worth.
Particularly this:

    export function worldToLocalArray(out: number[], u: number, v: number, h: number) {
        out[1] = h - cameraHeight
        let tx = u - cameraX
        let tz = v - cameraY
        out[0] = tx * cosHeading + sinHeading * tz
        out[2] = -tx * sinHeading + cosHeading * tz
    }

Love it, thanks! :+1:

2 Likes

Great, now all we need to do is program some power ups and the CPU player

Did anybody use the BOOST mechanic I made?

worldToLocalArray is a coordinate transformation. There are three coordinate systems being used:

  • World coordinates specify a location in the track map image. The code often refers to them as u and v (the usual convention for textures), and the current camera position (cx, cy) and player position (px, py) are in world coordinates. If you want to place an object in world coordinates, just open the track map in the image editor and look up the pixel coordinates. There’s also an h (height) component that’s just the distance up from the ground plane.
  • Local coordinates are a translated and rotated coordinate system that moves with the camera. Local X points to the right, local Y points up (that’s the h local direction), and local Z points backwards from the camera, at right angles to the screen. Its origin is the camera location, and the ground is cameraHeight units below the origin. heading is the forward-facing compass direction, with zero facing up (north) and 90 degrees right (east).
  • Screen coordinates are just pixel positions for drawing on the screen, with (0, 0) at the top left and (159, 119) at the bottom right.

So worldToLocalArray takes world u/v/h coordinates as inputs and produces local x/y/z coordinates as output. It does that by subtracting the camera’s position, and then rotating by heading degrees. Similarly, worldToScreenArray transforms world coordinates to screen coordinates, including the perspective calculation that shrinks far-away objects. The perspective calculation follows OpenGL conventions, see for example here: http://www.songho.ca/opengl/gl_projectionmatrix.html

The Array variant of the function is just an efficiency improvement. Instead of returning a fresh array with the results, it stores the values in a caller-supplied array. That avoids allocating memory and reduces stress for the garbage collector. There’s also a plain worldToLocal variant which returns a fresh array, it’s a bit more convenient to use (the debug cubes use it), but is less efficient.

3 Likes

This is what I have now! It has pipes that work and are placeable now!

In the original V0.2 (that was going to get posted, but I fixed the game before the post was approved and deleted that post), the game lagged a lot (with random lag spikes worse than Minecraft Java), but I did an optimization that would only render the pipes in a range of 100 pixels so now the framerate is stable.

I will probably implement more tracks, playable characters, thwomps, MKSC style item boxes, items, cpu racers, and maybe even trees if it doesn’t lag too much.

2 Likes

@kwx Thanks for your so detail explainations. Make my understanding about these concepts more clear.
What I strugled with is

        out[0] = tx * cosHeading + sinHeading * tz
        out[2] = -tx * sinHeading + cosHeading * tz

At first I drew out, and understood the relationship between them. But it’s “-” instead of “+” at front of Y part in my result, like this:

        out[0] = tx * cosHeading - sinHeading * tz
        out[2] = -tx * sinHeading - cosHeading * tz

until I realized the Y( or v) and cy are “points down” in world coordinates. I used the coodination in my math class. :smile: But even after I knew this, still take a long time to adopt it in mind.

BTW, I love it because so effient it is, no angle calculation and the cosHeading/sinHeading are only trigonomic functions invovled, that can be reused in entire update() each time.
Thanks again, I learned a lot!

2 Likes

I’ve made bug fixes, item boxes (animations coming soon) with green shells that bounce off of walls and can hit you and mushrooms that speed you up. I’ve made turning work according to how fast you move, as well as better collision which checks your position for every pixel you move every frame instead of just your position every frame.

1 Like

If you guys want me too I know how to do really good art from images on google it takes a while but it’s fun and I’d like to be of help

how’s the game going?

Here’s a new version. It has trees, drifting, a lap timer, and other major changes.

(For historical interest, there’s also the earlier version 1.8.3 which I had tried to post on Friday but it hadn’t made it to the forum. That one had similar features but was slower due to using floating point math.)

Gameplay and user-visible changes:

  • Some basic car physics with inertia and drifting. It’s not at all realistic, but I think it’s kind of fun. Press A to boost, and B to drift. There’s a drift practice track in the northeast corner of the map.
  • Terrain slowdown/collisions
  • A lap timer triggered by crossing the finish line. (Yes, it’s possible to cheat. It would need check points to avoid that.) The score display is based on the lap time.
  • Improved performance on hardware compared to version 1.8.3 - I’m getting about 14fps on the PyGamer with trees enabled.

Internals changes:

  • Blocks support! The new Renderer category has “place image”. There’s two versions that both do the same thing, the “placed image is visible” one is useful if you need to change logic depending on if the image is in view or not. See version 1.8.3 for a demo of that.
  • The object drawing is now based on blitting images directly instead of scaling sprites, this should be a lot more efficient. It does its own visibility checks and Z sorting. I think you shouldn’t need the 100-pixel range limit anymore. (If it’s still an issue, use renderer.setZClipFar(distance) to adjust the render distance.) By default the images are attached at the bottom center, you can change that with the optional anchor parameter. The code is a bit less readable due to using fixed-point math, but that’s a lot more efficient.
  • Updated the background renderer to scale the image to match the field of view - this isn’t pretty but helps avoid motion sickness. You can use renderer.setBackgroundSolidColor(col) instead of renderer.setBackgroundImage if you prefer. I had added lots of comments about this, but the Blocks conversion deleted them. Sigh.
  • The renderer and maths code now live in separate files to de-clutter the Blocks view. To import this, use JavaScript mode, open Explorer at the left, and copy the renderer.ts and fx14.ts files to your own project. (This would be nicer as an extension, but I haven’t had time to package it yet.) I hope this will make it easier to import future changes.
  • Some fixes to the projection code to better attach objects to the ground. This slightly changes the visible view, you may need to tweak zNear and zFar to compensate.
  • The coordinate system is now based on texture pixel centers, not edges. This way, you don’t need to add 0.5 to center objects on pixels.

There’s also a few possible regressions where things work differently:

  • The player car is now always drawn in front of the 3d images. If that’s an issue, let me know - it’s fixable but I’m not sure if people care.
  • I removed the pixel-accurate attachX/attachY, let me know if you need this back. The new anchor (default is bottom center attachment) seemed simpler.
6 Likes

Thanks so much for all these optimizations! Are you done working on this project, or are you still working on the engine? I think the engine is pretty good in its current state and I could start making an official game with it if that’s okay with you. I was thinking I’d include some custom tracks, some smk tracks, some mksc tracks, and (maybe) some CTR Nitro GBA tracks. Anyone can help if they want to, but if you’re done @kwx, I’d like to add some features like stitching images together (to have a high track resolution, hopefully stitching up to 16 images to make some of the GBA tracks at their original quality.) I will also probably add back in projectiles to your new version, and more items. I just want to know if you are still working on this project so I don’t start an official development and have it be a few versions behind. ITS TOTALLY OKAY THOUGH IF YOU ARE STILL WORKING ON THIS, just please tell me. Also, I don’t really care about changes listed in the bullet points at the bottom of your post as it wouldn’t really affect a 2.5d racing game clone.