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.
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.
I have a pipe sprite - I just need to know how to position it on-screen the best.
I tried many things (then deleted the blocks that I tried), but I just don’t have ideas on
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!
@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.
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.
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
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!
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:
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.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).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.
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.
@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. 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!
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.
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:
Internals changes:
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.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.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.zNear
and zFar
to compensate.There’s also a few possible regressions where things work differently:
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.