Beginner in creating games - My first game inspired by Hill-Climb "race" games

Hello, hello!

As the title suggests, I started about a month ago looking into making a little video game.
I’m totally aware of how hard it can be, so I decided to make something pretty basic that wouldn’t require too many constraints, which is why I chose 2D Physics and a vehicle (movements on a 2D plan, no animation whatsoever).

I’ve got some knowledge in 3D modeling (Cinema 4D) as an amateur, but I suck at 2D, I just can’t draw anything, or it takes me forever and I’m usually not satisfied with the result, so making textures is a painful tedious task.

First of all, I’d like to apologize in advance as I’m a complete beginner, like, I know nothing about Unity, I can’t even figure out (yet) how shaders work, or to move the axis of an object (like in C4D, which is very useful to rotate objects or even reset it without impacting the mesh) although I read it wasn’t possible, which I hope isn’t true.
Basically, I’m not here to ask you to tell me how to do everything, which would be verily boring, but I’d like to share my experience and steps through that “adventure”. So please don’t give me a “RTFMN”. :stuck_out_tongue:
Of course, I’ll appreciate your help once I get really stuck (very likely to happen, right?).

When I started that project, there are 2 things that I absolutely wanted to figure out:

  1. how to make a vehicle and see how hard it’d be
  2. if it was possible to use a 3D object with 2D physics (sorry, I don’t know how to call that, as saying "Unity 2D’ sounds quite improper)

For 1), thanks to all the tutorials on YouTube, I quickly got my answer.
For 2), importing FBX files works pretty well except that there is something really strange about the axis, as it seems that the model has to be oriented in the right way beforehand, or else even having rotated it won’t let us to put the Wheel Colliders as we want (the wheels get aligned on another axis, not the object’s). Also, the ways the materials work are… peculiar to me.

Needless to say that I followed quite many tutorials, in 2D and 3D physics, but overall I’ve been disappointed in the results. Not even one talked about braking in a “realistic” way. By realistic, I mean “likely”, obviously I’m not expecting any simulation with crazy equations.

So that leads us to my first code.
It’s a mix of things I learned here and there, and a hand-crafted part for the brakes that is probably going to scare some. :smile:
It’s based on my own logic (and ignorance in C Sharp) as everything I tried before having that working didn’t want to work. Lack of knowledge, undoubtedly.
It works, I’m not satisfied at all, but that’s all I could come up less than 2 weeks after having begun.

I’m not asking you to give me any tips if you don’t want to :wink:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))]

public class CarController2DPhysics : MonoBehaviour
{
    [SerializeField]
    private Vector3 _centerOfMass;

    public float speed = 4000;
    public float rotationSpeed = 4000f;
    public WheelJoint2D rearWheel;
    public WheelJoint2D frontWheel;   
    private Rigidbody2D rb;
    private float movement = 0f;
    private float rotation = 0f;
    private float brake = 0f;
    private float nospeed = 0.1f;
    private bool moveForward;
    private bool moveBackward;


    private void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        rb.centerOfMass = _centerOfMass;
    }

    void Update()
    {
        movement = -Input.GetAxisRaw("Vertical") * speed ;
        brake = -Input.GetAxisRaw("Vertical") * nospeed;
        rotation = Input.GetAxisRaw("Horizontal");
        moveForward = (Input.GetKey(KeyCode.UpArrow));
        moveBackward = (Input.GetKey(KeyCode.DownArrow));
    }

    void FixedUpdate()
    {
        rb.AddTorque(-rotation * rotationSpeed * Time.fixedDeltaTime);

        if (movement == 0f)
        {
            //rearWheel.useMotor = false;
            frontWheel.useMotor = false;
        }
        //}
        else if (moveForward)
        {
            //rearWheel.useMotor = true;
            frontWheel.useMotor = true;
            JointMotor2D motor = new JointMotor2D { motorSpeed = movement , maxMotorTorque = frontWheel.motor.maxMotorTorque };
            //rearWheel.motor = motor;
            frontWheel.motor = motor;
       
        }

       
        if (moveBackward)
        {
            if (GetComponent<Rigidbody2D>().velocity.x > 0.5)
            {
                frontWheel.useMotor = true;
                JointMotor2D motor = new JointMotor2D { motorSpeed = brake, maxMotorTorque = frontWheel.motor.maxMotorTorque };
                frontWheel.motor = motor;
            }

            else if (GetComponent<Rigidbody2D>().velocity.x < 1)
            {
                frontWheel.useMotor = true;
                JointMotor2D motor = new JointMotor2D { motorSpeed = movement, maxMotorTorque = frontWheel.motor.maxMotorTorque };
                frontWheel.motor = motor;
            }
        }

        if (moveForward)
        {
            if (GetComponent<Rigidbody2D>().velocity.x < -0.5)
            {
                frontWheel.useMotor = true;
                JointMotor2D motor = new JointMotor2D { motorSpeed = brake, maxMotorTorque = frontWheel.motor.maxMotorTorque };
                frontWheel.motor = motor;
            }

            else if (GetComponent<Rigidbody2D>().velocity.x > -1)
            {
                frontWheel.useMotor = true;
                JointMotor2D motor = new JointMotor2D { motorSpeed = movement, maxMotorTorque = frontWheel.motor.maxMotorTorque };
                frontWheel.motor = motor;
            }
        }



    }
}

And finally, a video of my in-game test I made before starting that thread (I’ve been focusing on my models and mainly the textures for the past 2 weeks):

I hope you’ll enjoy that thread, I’ll do my best to make it pleasant and share many interesting things.

2 Likes

Good day, everyone! (to be said aloud doing Prof Farnworth’s voice)

I actually wrote a long message 6 days ago, but it was seen as “spam-like”.

So I’ll write shorter messages, and share the links from my blog where it’s more thorough.
(note: no advertisement at all, no newsletter, no annoying stuff whatsoever)

Here is the video I wanted to share on 20th:

I added the drag option to slow down the car ONLY when the up/down arrow keys aren’t pressed AND when the front wheels are touching the ground.
I learned how to call stuff from another script, which took me a while to figure out.
And here: My first game in Unity part4 – Slowing down the car smoothly – munchou.com the article I wrote where I explain my process and of course the code.
I bet that’s not the way it should be done, but it works, so for now that’ll do. I think that’s a decent workaround.

Don’t hesitate if you have suggestions/questions/remarks.

I’ll try to write more here next time, but if it’s to be forbidden from posting again… pfff…

1 Like

I think the physics are looking good! The truck seems to have some feeling of weight to it, which is better than what most “simple”(?) games have.
Btw, what platform are you making the game for?

It´s looking pretty good for your first game!

I remember my first project and trying to create driving physics for a car, following a tutorial, also I can´t code for crap so I´m thankful for helpers like Playmaker and vehicle physics packages.
Your physics seem much more stable than mine were :smile:

Hi Artoodiitoo (nice nickname :sunglasses:),
Thank you, I’m glad to read that the physics look decent!
Indeed, I followed many tutorials (most of them on YouTube), and even famous Unity channels delivered, in my opinion, poor results. When one teaches something, shouldn’t it be thorough? Then we can decide to use whatever we need.
I saw better ones when it comes to 3D physics, not much about 2D, so I really feel I’m tweaking more than doing what should be done.

And because it’s my first game and it’s going to be a “small” one (although I’ve got many ideas I’d like to implement, but I don’t want to be greedy and in the end give up), I was thinking of making it for Android (and PC of course), to play on my tablet. Mainly for study purposes, to see how everything runs, how many polygons and effects can be displayed, how optimization works, etc.
But well, it’s just a try, I don’t know how it’s going to perform, I read that using transparent textures could bring issues, but no elaborated topics about it (benchmarks, etc.), so we’ll see, because for vegetation, no transparency means too many polygons for such little GPU.
I don’t have an iPhone, so I won’t be able to test it, but I could release it anyway for whoever would wish to try it.

Lately I’ve mainly been working on the environment, trying things here and there.
I also made a speedometer and fuel gauge, I’ll talk about that in another post.
Here are a few in-game (Unity) pictures of what I’ve made:

Started a forest-like past, made fem plants (I think they look fine). I wanted to see if it would bug or run poorly, but it ended up fine. I used the “cut-out” option, I like the way it renders in that case.
The trees don’t have a top, and we can easily see with the shadows that it was a bad idea. I won’t modify that for now as it seems that the shadows cannot be rendered that way on Android (unless one likes playing at 3FPS), to be checked on a not too old device.


I started making a (traditional) Japanese house (newly built houses in Japan are completely different, nothing fancy anymore, dull designs). I forgot to update the model, so you can’t see the stone lantern.


Here is the lantern. Original photograph from the web, then model in Cinema 4D. I’m quite satisfied with the model although I wish I could add moss here and there. But unwrapping and working on textures is way too time consuming (and frustrating).


Closer view of the trees (C4D). They are all the same, I only rotated them along the path.

Hey hey hooooo!

More stuff added, starting with a speedometer AND a fuel gauge.
So this is what it looks like in-game (speed, fuel being used up, behavior when it’s empty):

Because there is a lot to say, if you’re interested about the code and the how I did, check the posts on my website:
Update of the code - I realized that there was an issue with the way I wrote the drag code to slow down the car, so I modified it a little. It’s a bit strange OnTriggerStay2D works once, but doesn’t reset itself once the collision is off, so I had to add OnTriggerExit2D.
Adding a speedometer - Thanks to a well-explained tutorial on YouTube (I shared the link), I was able to make one.
Fuel gauge and fuel consumption - Based on the speedometer, I made a fuel gauge, and many other things to make the petrol consumption work and what happens when the car runs out of gas.

You can also see I made a few more models (warehouse, crappy office, modern Japanese house), I’ll share more screenshots about them later. They look not bad, I just find the in-game render in Unity not appealing at all, I hope there is a way to make something prettier to the eyes.

Next step: to add a delivery system, and I’ll explain more about what I intend to do.

Laterzzzzzzz!

Buenos dias muchachos!

I was busy (and lazy), so I only got back to it this evening…

I switched to a more classic side view (I’ll keep it like that for now, maybe forever) and decided to create a “dynamic” camera that reacts to the speed of the truck and that is smooth.
It took me a little time to get a decent result, the first thing I tried was depending directly on the speed and - logically - ended up being too rough.

So after a little research, I found the Vector3.SmoothDamp, which didn’t work quite as intended, probably because I’m using it in 2D instead of 3D? Not sure, but what is shared in the manual was affected by the rotation of the truck on the Z axis, which was leading the camera to either move up or down on the Y axis (in the air), depending on the rotation.
Instead of using
Vector3 targetPosition = target.TransformPoint(new Vector3(0, 5, -10));
I used
Vector3 targetPosition = new Vector3(some stuff here that I’m about to show you);

First, the code that works:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraSmoothFollow : MonoBehaviour
{
    public Transform target;
    public float smoothTime = 0.3F;
    private Vector3 velocity = Vector3.zero;

    public CarController2DPhysics Truck;
    private float speedX;
    private float speedY;
    private float speedZ;
    private float vehicleSpeed;

    void FixedUpdate()
    {
        vehicleSpeed = Truck.realSpeedInKPH;
        speedX = vehicleSpeed / 4.5f;
        speedY = vehicleSpeed / 50f;
        speedZ = vehicleSpeed / 4.55f;

        // Define a target position above and behind the target transform
        Vector3 targetPosition = new Vector3(target.position.x + 3 + speedX, target.position.y + 3 + speedY,
            target.position.z - 15 - speedZ - Mathf.Abs(target.position.y /2));

        // Smoothly move the camera towards that target position
        transform.position = Vector3.SmoothDamp(transform.position, targetPosition, ref velocity, smoothTime);
    }
}

I’m not sure that’s the right way to do it, but Jack65423 (one of my most diligent neurons) suggested me to consider the camera as a moving object between 2 positions (each position being given specific coordinates x, y, z). So the camera’s position at the start would be (relative to the followed object, here the truck) 3, 3, -15.
Little Jacky then told me to set the camera as I wished it to be at full speed (moved and zoomed out) and to write down the coordinates. I got (9.8, 4, -26). Those would be the numbers we’d get when the truck is at its maximum speed (50km/h in that case). So at 0km/h, we have (3, 3, -15), and at 50km/h (9.8, 4, -26).
By doing an extremely complicated subtraction, we can see how much the coordinates must “evolve”.
For example, for the Z axis, I created the speedZ value that is equal to the vehicle speed divided by 4.55. Where does 4.55 come from? I divided 50 (the max speed) by 11 (the difference between the final coordinates and the original ones). 50/11=4.55 (approx.).
Actually, for speedX, it should be around 7.4, but I wanted the camera to much more to the right side in order to let the truck move to the left, hence giving the player a better of what’s to come on the road.

speedX, Y and Z vary depending on the speed, which means they are equal to 0 when the truck isn’t moving, and they’ll reach the desired end value when the speed is at its maximum.
Knowing that, Bob687 finished the job with the Vector3 formula.
In case you don’t know, it’s Vector3(x, y, z)
Which gives us:
new Vector3(target.position.x + 3 + speedX, target.position.y + 3 + speedY, target.position.z - 15 - speedZ - Mathf.Abs(target.position.y /2));
For x: target.position.x + 3 + speedX
For y: target.position.y + 3 + speedY
For z: target.position.z - 15 - speedZ - Mathf.Abs(target.position.y /2)
Why is z so different? Because I noticed that when the truck goes high and jumps, the ground disappears and it’s not possible to anticipate anything (and honestly, it doesn’t look pretty). So I added one more thing that depends on the position of the truck on the Y axis. I divided by 2 so that the zoom out wouldn’t be extreme. Now it looks quite natural.
Oh yes, to zoom out (on the Z axis), the camera goes into the negatives, therefore it is necessary to subtract.
Also, because the truck goes up and down on the Y axis, I added the Mathf.Abs so that even when the Y is negative, it’s converted into a positive and the camera won’t zoom in unexpectedly (although I haven’t tested it, but I believe it should work).

That’s it.
One small issue, however: because I set the speedX to have the camera move to the right, it does the opposite if the truck goes reverse, and it disappears (or almost). I think it’s easily fixable with a condition (when the velocity is negative).

A super short video (not even 30 seconds) to see the result:

Indeed dear self, the theory was right.

So here’s the updated part: (only delete speedX and add the if and else)

    void FixedUpdate()
    {
        vehicleSpeed = Truck.realSpeedInKPH;
        //speedX
        if (Truck.rb.velocity.x < 0)
        {
            speedX = vehicleSpeed / 25f;
        }
        else
        {
            speedX = vehicleSpeed / 4.5f;
        }

        speedY = vehicleSpeed / 50f;
        speedZ = vehicleSpeed / 4.55f;

Important: to be able to have access to the rb.velocity.x of the Truck, one must change (in the truck’s script) private Rigidbody2D rb; into public Rigidbody2D rb; .

Now, when the truck moves backward (on the X axis), the camera will keep the truck in view (with even a little space on its left). Satisfying result in my case, because that’s what I intended to get.