Tag Archives: reactjs

Creating a Car Game in React – Part 2 – Steering and Obstacles

In the second part of this series, we’re going to add some steering to our car, and introduce a concept of obstacles. If you’re wondering what this is the second part of, please start here.

The GitHub repo for this post can be found here.

In the first post of the series, we added a car, and allowed the user to move it around the screen in a very crude fashion; here, we’re going to change the controls to feel a little more like a car. As with the previous post, not every single change will be here, but it will be in the GitHub repo above.

Steering and Acceleration

Let’s have a look at the controls in the Game component:

onKeyDown now looks a little different:

onKeyDown(e) {
	switch (e.which) {
		case 37: // Left
			this.playerSteer(-10);
			break;
		case 38: // Up
			this.playerAccelerate(0.3);
			break;
		case 39: // Right
			this.playerSteer(10);
			break;
		case 40: // Down
			this.playerDecelerate(-0.5);
			break;
		default:
			break;
	}
} 

So, we’re no longer simply repositioning the car, but applying forces to it. Initially, I had Down as simply a negative acceleration, meaning that if you break too hard, you go backwards! Here’s the three functions referenced above:

playerAccelerate(speed) {
	this.setState({
		playerMomentum: this.state.playerMomentum + speed
	});
}

playerDecelerate(speed) {
	if (this.state.playerMomentum > 0) {
		this.setState({
			playerMomentum: this.state.playerMomentum + speed
		});
	} else if (this.state.playerMomentum < 0) {
		this.setState({
			playerMomentum: this.state.playerMomentum - speed
		});
	}

}

playerSteer(direction) {
	this.setState({
		playerRotation: this.state.playerRotation + direction
	});
}

There are a number of new state variables, which I won’t list here. However, because we are no longer repositioning the car based on the user action, we need to apply the forces that we are changing; that is, we need a game loop.

Game Loop

The game loop code is relatively complex. Looking at this should make you seriously consider using a a game engine of some description:

gameLoop() { 
	const radians = (this.state.playerRotation - 90) * Math.PI / 180; 
	const aX = (this.state.playerMomentum * Math.cos(radians));
	const aY = (this.state.playerMomentum * Math.sin(radians));
	const velocityX = this.state.playerVelocityX;
	const velocityY = this.state.playerVelocityY;
	const velocitySq = Math.pow(velocityX, 2) + Math.pow(velocityY, 2);
	const posSq = Math.pow(aX, 2) + Math.pow(aY, 2);
	const velocityPosSq = Math.pow(velocityX * aX + velocityY * aY, 2);
	let skidFactor = (posSq == 0 || velocitySq == 0) ? 0 : 1 - (velocityPosSq / posSq / velocitySq);
	
	if (skidFactor <= 0) skidFactor = 0; 
	
	this.setState({
		playerVelocityX: (skidFactor * velocityX) + ((1 - skidFactor) * aX),
		playerVelocityY: (skidFactor * velocityY) + ((1 - skidFactor) * aY)
	}); 
	this.playerMove(
		this.state.playerX + this.state.playerVelocityX,
		this.state.playerY + this.state.playerVelocityY 
	);
	this.playerDecelerate(-(0.1 + skidFactor));
}

If you’re wondering where this brain-melting maths comes from, have a look here.

I’ve split it up in an effort to make it slightly more understandable, but the premise is that if you’re travelling fast and change direction suddenly, it doesn’t immediately turn. Again, if you’re thinking you don’t want to be messing around with this kind of thing then a lot of game engines take care of this for you.

Obstacles

Finally, we have our obstacles. There is no collision just yet, but this basically puts pictures of trees around the screen (incidentally, I did all the artwork myself, which I assume the reader to be suitably impressed by!) We’ll come back to this later to make the collision work:

buildObstacles() {
	let obstacles = [];
	const obstacleCount = Math.floor(Math.random() * 10) + 1;
	console.log('Obstacle count ' + obstacleCount);
	for (let i = 1; i <= obstacleCount; i++) {
		const centreX = Math.floor(Math.random() * this.state.windowWidth) + 1;
		const centreY = Math.floor(Math.random() * this.state.windowHeight) + 1;
		
		obstacles.push(<Obstacle key={i} image={treeImg} centreX={centreX} centreY={centreY} width={this.spriteWidth} height={this.spriteHeight} />);
	}
	return obstacles;
}

All this function does is build up an array of HTML; we then feed that into a class variable in the constructor:

constructor(props) {
	super(props);
	document.body.style.overflow = "hidden";
	this.state = {
		playerX: 100,
		playerY: 100,
		windowWidth: 1500,
		windowHeight: 1500,
		playerMomentum: 0,
		playerRotation: 0,
		playerVelocityX: 0,
		playerVelocityY: 0
	};
	this.spriteWidth = 25;
	this.spriteHeight = 25;
	this.updateWindowDimensions = this.updateWindowDimensions.bind(this);
	this.onKeyDown = this.onKeyDown.bind(this); 
	this.obstacles = this.buildObstacles(); 
}

(It’s worth noting, as an aside, that we are preventing scrolling here by setting document.body.style.overflow)

Finally, we’ll display it in the render method:

render() { 
	return <div onKeyDown={this.onKeyDown} tabIndex="0">
		<Background backgroundImage={backgroundImg}
		windowWidth={this.state.windowWidth} windowHeight={this.state.windowHeight} /> 
		
		<Car carImage={carImg} centreX={this.state.playerX} 
		centreY={this.state.playerY} width={this.spriteWidth}
		height={this.spriteHeight} rotation={this.state.playerRotation} /> 
		
		{this.obstacles} 
	</div>
}

This technique allows you to build an array of HTML objects dynamically. The thing to notice here is the ‘key’ that we’re passing through; if you don’t pass this, you’ll start getting the following error:

Each child in a list should have a unique “key” prop.

In the next post, we’ll introduce collision.

References

https://stackoverflow.com/questions/5192983/calculating-x-y-movement-based-on-rotation-angle

https://gamedev.stackexchange.com/questions/172571/how-to-implement-a-slight-skid-in-a-car-game

https://stackoverflow.com/questions/39962757/prevent-scrolling-using-css-on-react-rendered-components

Creating a Car Game in React – Part 1 – Drawing and Moving

Since I started looking at React, I’ve wondered whether it would be possible to create a multi-user game. The game would look a little like a Spectrum game that I used to play called: Trans-Am. I’m guessing most people reading this are not going to be old enough to remember this. Essentially, it marks the peak of car game development, and everything has been down hill ever since.

If you have no idea what I’m talking about then there’s a demo of the game here.

I’m not going to try and emulate this exactly, I thought I’d use it as a basis to make a multi-player car game.

The GitHub repository for this post can be found here.

Create a React Application

We’ll start by creating a new React Application (see here for details):

Now we have the application, we’ll need some game assets. If you want to use the same assets as me then feel free to pull my repository. However, at this stage, all you’ll need is a square box and a green screen.

Game Layout

The next stage is to design the game layout; because this is React, we’ll start with App.js. We’ll delegate all of our game logic to a component called Game:

import React from 'react';
import './App.css';
import Game from './Components/Game';
function App() {
	return (
		<div className="App">
			<Game />
		</div>
		);
}
export default App;

If you want to see, comprehensively what Game.Jsx looks like, then have a look at the latest version on GitHub. However, some of the highlights are the render method:

render() { 
	return <div onKeyDown={this.onKeyDown} tabIndex="0">
		<Background backgroundImage={backgroundImg}
		windowWidth={this.state.windowWidth} windowHeight={this.state.windowHeight} /> 
	<Car carImage={carImg} centreX={this.state.playerX} 
		centreY={this.state.playerY} width={this.playerWidth}
		height={this.playerHeight} /> 
	</div>
}

This will probably change as to game progresses, but at the minute, it just renders to two constituent components. We’re also responding to KeyDown here, so let’s have a look at onKeyDown:

onKeyDown(e) {
	switch (e.which) {
		case 37: // Left
			this.playerMove(this.state.playerX - this.SPEED, this.state.playerY); 
			break;
		case 38: // Up
			this.playerMove(this.state.playerX, this.state.playerY - this.SPEED);
			break;
		case 39: // Right
			this.playerMove(this.state.playerX + this.SPEED, this.state.playerY); 
			break;
		case 40: // Down
			this.playerMove(this.state.playerX, this.state.playerY + this.SPEED);
			break;
		default:
			break;
	}
} 

playerMove(x, y) {
	this.setState({
		playerX: x,
		playerY: y
	}); 
}

We’re storing the players position in state; as I detailed here, this enables us to update the state and have React update the screen as it detects a change in the Virtual DOM.

Game Components

In an effort to stay as close as possible to React’s preferred architecture, the components of the game (the background and the cars for now) will be, well, components. Background is easy:

import React from 'react';
function Background(props) {
	const bgStyle = { 
		width: `calc(${props.windowWidth}px)`, 
		height: `calc(${props.windowHeight}px)`, 
		top: 0,
		left: 0,
		position: 'absolute' 
	};
	return (
		<img src={props.backgroundImage} style={bgStyle} />
	);
}
export default Background;

We’re basically just displaying an image here. One thing that’s worth noting is that the windowWidth and windowHeight are properties, not state. They do exist as state in the Game component and, when they change, are updated there, and so updated here. The React guys call this Lifting State.

The car component is exactly the same idea:

import React from 'react';
function Car(props) {
	const left = Math.round(props.centreX - (props.width / 2));
	const top = Math.round(props.centreY - (props.height / 2));
	const carStyle = { 
		width: `calc(${props.width}px)`, 
		height: `calc(${props.height}px)`, 
		top: `calc(${top}px)`,
		left: `calc(${left}px)`, 
		position: 'absolute',
		zIndex: 1 
	};
	return (
		<img src={props.carImage} style={carStyle} />
	);
}
export default Car;

There are a number of advantages to this idea of maintaining the state in a higher component; for example, this way, you can share a single state between components; however, the biggest advantage for us is that, while the components are, effectively, intelligent sprites, you can easily create an “EnemyCar” version of the Car component.

It’s worth bearing in mind that, because the position of the car doesn’t exist in this component as state, we wouldn’t be able to change it here, even if we wanted to. The strategy to get around this is to have an update function passed in as a property (effectively a function pointer that you can call from within the child component).

In the next post, I’m going to update the movement so it’s a little more car-like, and introduce some obstacles.

References

https://reactjs.org/docs/components-and-props.html

https://stackoverflow.com/questions/43503964/onkeydown-event-not-working-on-divs-in-react

https://stackoverflow.com/questions/37440408/how-to-detect-esc-key-press-in-react-and-how-to-handle-it/46123962

https://reactjs.org/docs/lifting-state-up.html

https://stackoverflow.com/questions/36862334/get-viewport-window-height-in-reactjs

A C# Developer’s Guide to: ReactJS – Part 3 – Conditionally Rendering HTML in React

This is the third in a series of posts on interesting things I’ve discovered about React; the first of these can be found here.

One of the things that tripped me up early on while I was learning React (not that I’m a fully-fledged expert now or anything) was how to display HTML elements based on a given criteria. For example, say you only want to display a label while the form is loading, or you want to display a message based on other information on the screen.

If you were using a desktop binding architecture, say MVVM, you would bind the visibility to a visible property. Likewise in HTML, you may have a conditional style based on the bound model property. Let’s see how you might do that in React.

Create a new React Application

Let’s start by creating a new React application (using bash here):

This isn’t a particularly fast process, so maybe it’s time to get a brew.

Once it’s done, and assuming you have VS Code installed (if you don’t then go and install it from here), type:

code testreactapp

And as if by magic, VS Code appears!

You should be able to run this straight out of the box. Start a new terminal in VS Code, and type npm start:

The displayed screen is of a little animated spiragraph. Let’s add a button and, where the user presses the button, hide or show the spinning spiragraph.

State

As I have previously written about here state is one of the key concepts in React. Let’s create a state object that will determine the visibility of our animation.

In order to introduce state, we need to change the default app.js to be a class, as functions cannot have state. Note that, were this a real application, you would probably move this out into a separate component; but let’s change our app.js to be a class:

import React, {Component} from 'react';
import logo from './logo.svg';
import './App.css';

export default class App extends Component {
	render() {
		return (
			<div className="App">
				<header className="App-header">
					<img src={logo} className="App-logo" alt="logo" />
					<p>
						Edit <code>src/App.js</code> and save to reload.
					</p>
					<a
					className="App-link"
					href="https://reactjs.org"
					target="_blank"
					rel="noopener noreferrer"
					>
						Learn React
					</a>
				</header>
			</div>
		);
	}
}

All I’ve done here is change the function to a class, and added `import {Component}`.

Now let’s add some state. At the top of the class, add a constructor:

constructor(props) {
	super(props)
	this.state = {
		showSpiragraph: true
	}
}

Let’s now add the button, so we can change the value of the state; first, we’ll need the button itself:

. . .
	<a
		className="App-link"
		href="https://reactjs.org"
		target="_blank"
		rel="noopener noreferrer"
	>
		Learn React
	</a>
	<button onClick={this.toggleShow}>Hide/Show</button>
</header>
. . .

Then the function that we’re calling (toggleShow):

toggleShow = () => {
  this.setState(state => ({showSpiragraph: !state.showSpiragraph}));
}

If you run this now, it will allow you to press the button until your finger aches, but it won’t actually do anything.

Conditionally Displaying an Element

Okay, so we come to the crux of the entire post; we can conditionally render our image by using the following syntax:

. . .
<header className="App-header">
  {this.state.showSpiragraph &&
    <img src={logo} className="App-logo" alt="logo" />
  }
. . .

You should now be able to click the button and have the Spiragraph show and hide at will.

References

https://medium.freecodecamp.org/quick-guide-to-understanding-and-creating-reactjs-apps-8457ee8f7123

https://reactjs.org/docs/handling-events.html

A C# Developer’s Guide to: ReactJS – Part 2 – Moving Controls

Following on from my previous post, I’m going to extend our ReactJS application by adding some boxes, and allowing the user to re-arrange them on the screen.

Concepts

There are two key concepts to consider when working with React, and we’ll cover one of them in this post; that is: state.

React has a special property of each component known as state. If you use that to bind any of the UI to, then React will refresh that component when the state changes.

Moving a UI Element

Okay – that sounds great, but how would we do this in practice?

Imagine that you have a HTML box drawn on the screen; you might have something like this:

<div style="height:100px; width:200px; background:#0000FF" />

We can draw a box. If you use this code, then your box will be on the top left of the screen; so we can tell it not to be by specifying the left and top; let’s try defining a CSS style:

<div style="left:10px; top:20px;height:100px; width:200px; background:#0000FF" />

With React, we can set those values to a value derived from the state; for example:

render() {
    const top = this.state.newY;
    const left = this.state.newX;

    const myStyle = {
        height: '100px',
        width: '200px', 
        top: `calc(${top}px)`,
        left: `calc(${left}px)`, 
        borderStyle: 'solid',
        borderColor: 'blue', 
        position: 'absolute',
        zIndex: 1,
        background: 'blue'
    };

    return ( 
        <div> 
            <div style={myStyle}>source</div>
        </div>
    );
}

What this means is that every time I change the state values, the values in the style will update.

To illustrate this, if we write a React application like this (only the timeout function is new):

render() {
    const top = this.state.newY;
    const left = this.state.newX;
    const myStyle = {
        height: '100px',
        width: '200px', 
        top: `calc(${top}px)`,
        left: `calc(${left}px)`, 
        borderStyle: 'solid',
        borderColor: 'blue', 
        position: 'absolute',
        zIndex: 1,
        background: 'blue'
    };

    setTimeout(() => {
        this.setState({newX: this.state.newX + 1, newY: this.state.newY + 1});
    }, 50);

    return ( 
        <div> 
            <div style={myStyle}></div>
        </div>
    );
}

We can make out box move diagonally across the screen:

Screenshot included because you couldn’t possibly imaging what a blue rectangle looks like.

Start the app using VS Code

A quick note on VS Code. If you select Terminal -> New from the menu, you can run the React application directly from the IDE; and the best part is that if there’s something already running on the port, VS Code will just give you a new one:

Short Walks – Navigating in ReactJs

When you start using the React sample templates, one thing that you’ll notice is the navigation menu; it tends to look like this:

<div className='navbar-collapse collapse'>
    <ul className='nav navbar-nav'>
        <li>
            <NavLink to={ '/' } exact activeClassName='active'>
                <span className='glyphicon glyphicon-home'></span> Home
            </NavLink>
        </li>

After messing around for a while, you’ll probably think: now I need to navigate somewhere from within the code of the tsx/jsx file. Turns out you need to use `.push()`:

import { NavLink } from 'react-router-dom';

. . .

doSomething()
.then(output => {
    this.props.history.push('/timbuktu');
});

Not exactly intuitive. And even less intuitive is if you want to go back. You’re thinking it must be `.pop()`? So was I; it’s actually:

import { NavLink } from 'react-router-dom';

. . .

doSomething()
.then(output => {
    this.props.history.goBack();
});

Adding ReactJS to an existing Asp.Net Core 2 Application

I’ve recently been playing around with writing an Asp.Net Core 2 app from scratch. If you’re interested, you can view my exploits here.

I came across an interesting issue, which was that I wanted to search an in memory set of data, and I wanted the screen to update as I searched. React sounds like the perfect tool for this; and this article describes how to integrate a React view (JSX file) into an MVC view.

(Note that it doesn’t cover implementing the search function – that will be the subject of a later post when and if I work out how to do it.)

Set-up

After you’ve created your Asp.Net Core 2 application, the first step is to install React; which is a NuGet package:

Install-Package React.AspNet -Source nuget.org

There are some code tweaks that are needed; the first is in startup.cs (which basically tells Asp to use React, and how to do so):

services.AddTransient< …
 
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddReact();
 
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
app.UseReact(config =>
{
    
});
 
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();

You’ll need to slightly change the signature of ConfigureServices, too:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
. . . 
    return services.BuildServiceProvider();
}

The next thing is to make React available to your views; in ViewImports.cshtml:

@using UsefulSites.Web
@using UsefulSites.Web.Models
@using UsefulSites.Web.ViewModels
@using React.AspNet
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

React Code

Next step is to create the ReactJs file:

class SearchBox extends React.Component {
    render() {
        return (
            <div className="search-container">
                <textarea>
                    Search Text
                </textarea>    
            </div>
        );
    }
}
 
ReactDOM.render(
    <SearchBox />,
    document.getElementById('content')
);

Then change the HTML file:

<div class="row">
    <div class="jumbotron">
        <div id="content"></div>
        <script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/react/16.4.0/umd/react.development.js"></script>
        <script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.0/umd/react-dom.development.js"></script>
        <script src="@Url.Content("~/js/search.jsx")"></script>
    </div>

As you can see, the React script references the div named “content” specifically.

References

https://reactjs.net/getting-started/aspnetcore.html

https://reactjs.net/getting-started/download.html

Short Walks – Submit a single row of data in ReactJS

While looking into the react sample app, I came across a scenario whereby you might need to pass a specific piece of data across to an event handler. A lot of the online examples cover data state; but what happens when you have a situation such as the one in the sample app; consider this:

In this instance, you want to pass the temperature of the line you’ve selected. The solution is quite simple, and documented here:

private renderForecastsTable(forecasts: WeatherForecast[]) {
    return <table className='table'>
        <thead>
            <tr>
                <th>Date</th>
                <th>Temp. (C)</th>
                <th>Temp. (F)</th>
                <th>Summary</th>
            </tr>
        </thead>
        <tbody>
        {forecasts.map(forecast =>
            <tr key={ forecast.dateFormatted }>
                <td>{ forecast.dateFormatted }</td>
                <td>{ forecast.temperatureC }</td>
                <td>{ forecast.temperatureF }</td>
                <td>{forecast.summary}</td>
                <td><button onClick={(e) => this.handleClick(e, forecast)}>Log Temperature!</button></td>
            </tr>
        )}
        </tbody>
    </table>;
}

Here, we’re passing the entire forecast object to the handler; which looks like this:

handleClick = (event: React.FormEvent<HTMLButtonElement>, forecast: WeatherForecast) => {
    console.log("timestamp: " + event.timeStamp);
    console.log("data: " + forecast.temperatureC);
}

https://reactjs.org/docs/forms.html

https://reactjs.org/docs/handling-events.html

Adding a New Screen to the React Template Project

In this post I started looking into ReactJS. Following getting the sample project running, I decided that I’ve try adding a new screen. Since it didn’t go as smoothly as I expected, I’ve documented my adventures.

The target of this post is to create a new screen, using the sample project inside Visual Studio.

Step 1

Create a brand new project for React:

If you run this out of the box (if you can’t because of missing packages then see this article), you’ll get a screen that looks like this:

Step 2

Add a new tsx file to the components:

Here’s some code to add into this new file:

import * as React from 'react';
import { RouteComponentProps } from 'react-router';
 
 
export class NewScreen extends React.Component<RouteComponentProps<{}>, {}> {
    public render() {
        return <div>
            <h1>New Screen Test</h1>
        </div>;
    }
}
 

The Javascript as HTML above is one of the things that makes ReactJS an appealing framework. Combine that with Typescript, and you get a very XAML feel to the whole web application.

Step 3

Add a link to the Navigation Screen (NavMenu.tsx):

<div className='navbar-collapse collapse'>
    <ul className='nav navbar-nav'>
        <li>
            <NavLink to={ '/' } exact activeClassName='active'>
                <span className='glyphicon glyphicon-home'></span> Home
            </NavLink>
        </li>
        <li>
            <NavLink to={ '/counter' } activeClassName='active'>
                <span className='glyphicon glyphicon-education'></span> Counter
            </NavLink>
        </li>
        <li>
            <NavLink to={ '/fetchdata' } activeClassName='active'>
                <span className='glyphicon glyphicon-th-list'></span> Fetch data
            </NavLink>
        </li>
        <li>
            <NavLink to={'/newscreen'} activeClassName='active'>
                <span className='glyphicon glyphicon-th-list'></span> New screen
            </NavLink>
        </li>
 
    </ul>
</div>

If you run this now, you’ll see the navigation entry, but clicking on it will give you a blank screen. It is just that scenario that motivated this post!

Step 4

Finally, the routes.tsx file needs updating so that it knows which screen to load when:

import * as React from 'react';
import { Route } from 'react-router-dom';
import { Layout } from './components/Layout';
import { Home } from './components/Home';
import { FetchData } from './components/FetchData';
import { Counter } from './components/Counter';
import { NewScreen } from './components/NewScreen';
 
export const routes = <Layout>
    <Route exact path='/' component={ Home } />
    <Route path='/counter' component={ Counter } />
    <Route path='/fetchdata' component={FetchData} />
    <Route path='/newscreen' component={NewScreen} />
</Layout>;

Forcing an NPM Restore

I’ve recently started looking into the Javascript library ReactJS. Having read a couple of tutorials and watched the start of a Pluralsight video, I did the usual and started creating a sample application. The ReactJS template in VS is definitely a good place to start; however, the first issue that I came across was with NPM.

Upon creating a new web application, I was faced with the following errors:

The reason being that, unlike NuGet, npm doesn’t seem to sort your dependencies out automatically. After playing around with it for a while, this is my advice to my future self on how to deal with such issues.

The best way for force npm to restore your packages seems to be to call

npm install

either from Powershell, or from the Package Manager Console inside VS.

Powershell

On running this, I found that, despite getting the error shown above, the packages were still restored; however, you can trash that file:

Following that, delete the node_modules directory and re-run, and there are no errors:

Package Manager Console

In Package Manager Console, ensure that you’re in the right directory (you’ll be in the solution directory by default, which is the wrong directory):

References

https://stackoverflow.com/questions/12866494/how-do-you-reinstall-an-apps-dependencies-using-npm