React Tips: 1 – Starting React on a Different Port

I came up with an idea to start a series of posts on React that offers small tips on things you can do, errors that you might get, and anything else that future me might find useful.

I started by creating a new react app. The intention being that I would have a reference repository on GitHub.

The first part of this concerns starting react on a different port.

Why?

There are a couple of reasons that you may choose to do this, but one is to get around the issue when running:

npm start

Something is already running on port 3000

How

Have a look in your project for a file called package.json. In there, you should see something like this:

{ 
"name": "react-demos",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-scripts": "3.0.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},

In the start section, you can add the port:

{ 
"name": "react-demos",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-scripts": "3.0.1"
},
"scripts": {
"start": "set PORT=3005 && react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},

The default port is 3000, so if you don’t specify a port, it will always try to start on 3000.

What if I don’t want to change the port / Why won’t react die?

You could try the following command is bash:

taskkill -F -IM node.exe

It should kill all of your React processes.

References

https://github.com/facebook/create-react-app/issues/1083

https://stackoverflow.com/questions/45544145/how-stop-after-running-react-scripts-start

Adding Logging to Client Side Blazor

Whilst there are some pre-built libraries for this, I seemed to be getting Mono linking errors. What finally worked for me was to install the pre-release versions of:

Install-Package Microsoft.Extensions.Logging -Version 3.0.0-preview6.19304.6
Install-Package Microsoft.Extensions.Logging.Console -Version 3.0.0-preview6.19304.6

Now, in your View Model, accept the Logger:

public MyViewModel(ILogger<MyViewModel> logger)

Then you can log as normal:

_logger.LogInformation("Hello, here's a log message");

You should now see the debug message in the F12 console.

You might be wondering why you don’t need to explicitly inject the logging capability; the reason is that:

BlazorWebAssemblyHost.CreateDefaultBuilder()            

Does that for you.

Using View Models in Blazor

Being new to Blazor (and Razor), the first thing that tripped me up was that the view seemed divorced from the rest of the application. In fact, this is actually quite a nice design, as it forces the use of DI.

For example, say you wanted to create a View Model for your view, you could register that ViewModel in the Startup:

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddTransient<MyViewModel, MyViewModel>();
        }

Note here that you don’t need an interface. If you’re only creating an interface for the purpose of this then that abstraction provides no benefit. That isn’t to say there may not be a reason for having an interface, but if you have one and this is the only place it’s used, you probably should reconsider.

The views in Razor / Blazor (at the time of writing) are *.razor files. In order to resolve the dependency inside the view, you would use the following syntax:

@page "/"
@inject ViewModels.MyViewModel MyViewModel

(Note that @page “/” is only in this snippet to orientate the code.)

You can call initialisation in the view model using something like:

@code {

    protected override async Task OnInitAsync()
    {
        await MyViewModel.Init();
    }    
}

And, within your HTML, you can reference the view model like this:

<div>@MyViewModel.MyData</div>

Magic. Hopefully more to come on Blazor soon.

Creating a Car Game in React – Part 5 – Levels and Time

This is the fifth part of a series (that began here).

In the last post, we added the concept of score. The car now can collect cups while avoiding trees; however, we don’t have any concept of what happens when there are no cups left.

In this post, we’ll add levels to the game, so that when you’ve collected all the cups, you move up. We’ll also introduce a time limit to make it progressively harder (as it currently stands, it’s not much of a challenge to collect the cups because you can take all day).

The source for this post is here. Again, not everything is in the post, so please refer to the repository.

Levels

Because we are creating levels, we’ll need to track the level that we’re on, so a new state property is in order:

this.state = {
	playerX: 100,
	playerY: 100,
	windowWidth: window.innerWidth,
	windowHeight: window.innerHeight,
	playerMomentum: 0,
	playerRotation: 0,
	playerVelocityX: 0,
	playerVelocityY: 0,
	playerLives: 3,
	playerCrashed: false,
	gameLoopActive: false,
	message: "",
	score: 0,
	level: 1,
	cupCount: 1, 
	remainingTime: 0
};

If you’ve followed this through from this first post, you may be asking yourself: “Is he ever going to refactor and clean this up!?”

To which I confidently respond:

“Probably!”

Anyway, you’ll notice that we have the level, the score, the time and the cup count. Advancing through the levels is conceptually just a number; here’s the code that completes a level:

completedLevel() {
	if (this.state.level >= 10) {
		this.updateMessage("Congratulations, you've completed the game");
	} 
	this.startLevel(this.state.level + 1);
}

startLevel is a slight refactor, which essentially sets the cup count and level to the new value – we’ll come back to that shortly.

You can only complete a level by collecting enough cups, so the trigger should be in the cup collection:

collectedCup(key) {
	this.setState({ 
		score: this.state.score + 1 
	});
	this.cups = this.cups.filter(cup => cup.key != key);
	this.updateMessage("Collected cup");
	if (this.cups.length == 0) {
		this.completedLevel();
	} 
}

As soon as we’re down to 0 cups, we call completedLevel.

Time

Now it’s time to have a look at the startLevel code:

startLevel(level) { 
	this.setState({
		level: level,
		cupCount: level * 2 
	}); 
	this.obstacles = this.buildObstacles(); 
	this.cups = this.placeCups();
	this.resetCarPosition();
	this.totalLevelTimeMS = (this.TOPLEVEL - (this.state.level - 1)) * 60 * 1000
	let startLevelTimeMS = (new Date()).getTime();
	this.endLevelTimeMS = startLevelTimeMS + this.totalLevelTimeMS; 
}

We’re working out when the user is out of time, and storing that in endLevelTime. Note that none of these are in state variables – the only state variable is in updated in the game loop:

let remaining = (this.endLevelTimeMS - (new Date()).getTime()) / 1000;
if (remaining <= 0) {
	this.updateMessage("Out of time!");
	this.playerDies();
}
this.setState({
	remainingTime: Math.round(remaining)
}); 

This is at the end of the game loop: we’re updating the remainingTime state variable, but first, we calculate it and, if it’s zero, the player dies (loses a life).

We need to tweak the code for the player dying, because otherwise the timer will never get reset:

playerDies() { 
	this.setState({
		playerLives: this.state.playerLives - 1,
		gameLoopActive: false
	});
	if (this.state.playerLives <= 0) {
		this.initiateNewGame();
	} else {
		this.startLevel(this.state.level);
	}
	this.repositionPlayer();
	this.setState({ 
		playerCrashed: false,
		gameLoopActive: true
	});
}

The last part is to make the time look a bit better with another of my patented icons. GameStatus.jsx should now return the following:

    return (      
        <div className="flex-container" style={flexStyle}>
            <label style={labelStyle}>
                Lives Remaining: {props.Lives}
            </label>
            <label style={labelStyle}>
                Score: {props.Score}
            </label>
            <label style={labelStyle}>
                Level: {props.Level}
            </label>            
            
            <div style={containerStyle}>  
                <img src={clockImg} style={imgStyle} />
                <div style={textDivStyle}>{props.RemainingTime}</div>
            </div>

            <label style={labelStyle}>
                {props.Message}
            </label>
        </div>  
    );

There are some new styles here so that the time appears over the clock icon:

    const containerStyle = {
        position: 'relative',
        textAlign: 'center',
        color: 'red'
    }

    const textDivStyle = {        
        position: 'absolute',
        top: '50%',
        left: '50%',
        transform: 'translate(-50%, -50%)',
        zIndex: 1,
        fontWeight: 'bold'
    }

    const imgStyle = {
        width: '100%',
        zIndex: 0
    }

In the next part, we’ll implement a high score table.

Creating a Car Game in React – Part 4 – Score

This is the fourth part of a series (that began here). So far, we have a game where you can whizz around the screen avoiding trees. This effectively encompasses most aspects of a game of this type; that is, you can move, and there is a something preventing you.

The next step is to introduce something for the player to try to do, and give a score based on that. In our case, our player is going to try and collect cups – as per the original game. The asset I’ve created for the cup is here. For anyone following this series, you may have noticed that my artwork is a little… crap.

The source for this post is here.

Cups

The first thing that we’ve done here is added some code to place a few cups around the screen; the code for this was essentially the same as build obstacles:

placeCups() {
	let cups = [];
	const cupCount = 1;
	for (let i = 1; i <= cupCount; i++) {
		const centreX = Math.floor(Math.random() * this.state.windowWidth) + 1;
		const centreY = Math.floor(Math.random() * this.state.windowHeight) + 1; 
		cups.push(<GameItem key={i} image={cupImg} centreX={centreX} centreY={centreY} width={this.spriteWidth} height={this.spriteHeight} itemType={2} />);
	}
	return cups;
}

In a later post, I hope to do a full refactor, but for now, we have a separate function. This is rendered in the same way as the obstacles:

render() { 
	return <div onKeyDown={this.onKeyDown} tabIndex="0">
		<GameStatus Lives={this.state.playerLives} Message={this.state.message} Score={this.state.score} />
		
		<Background backgroundImage={backgroundImg}
		windowWidth={this.state.windowWidth} windowHeight={this.state.windowHeight} /> 
		
		<Car carImage={this.state.playerCrashed ? brokenCarImg : carImg} 
		centreX={this.state.playerX} centreY={this.state.playerY} 
		width={this.spriteWidth} height={this.spriteHeight} 
		rotation={this.state.playerRotation} /> 
		
		{this.obstacles} 
		
		{this.cups} 
	</div>
}

Collecting cups

In order to collect something, the player must collide with it. We need to change the collision code slightly to make it a little more re-usable:

detectAnyCollision(rect1) { 
	// Have we crashed or left the screen
	if (this.detectOutScreen(rect1)) {
		return true;
	}
	let collided = this.detectGameItemCollision(this.halfWidth, this.halfHeight, rect1, this.obstacles);
	if (collided !== undefined) {
		return true;
	}
	return false;
}

detectGameItemCollision(halfWidth, halfHeight, rect1, gameItemList) {
	const collided = gameItemList.find(a => {
		var rect2 = {
			x: a.props.centreX - halfWidth, y: a.props.centreY - halfHeight,
			width: this.spriteWidth, height: this.spriteHeight
		};
		return (this.detectCollision(rect1, rect2));
	}); 
	return collided;
}

As you can see, we now have a function that returns the item that we collided with, rather than a simple boolean. We then use this at the end of the game loop to determine whether we collided with a cup:

// Check for collected cup
const item = this.detectGameItemCollision(this.halfWidth, this.halfHeight, rect1, this.cups);
if (item !== undefined) {
	this.collectedCup(item.key);
} 

Score

There’s little point in zooming around collecting cups, if there’s no permanent record, so we need to add a score. Let’s start with a state variable in game.jsx:

this.state = {
	playerX: 100,
	playerY: 100,
	windowWidth: 1500,
	windowHeight: 1500,
	playerMomentum: 0,
	playerRotation: 0,
	playerVelocityX: 0,
	playerVelocityY: 0,
	playerLives: 3,
	playerCrashed: false,
	gameLoopActive: false,
	message: "",
	score: 0
};

And here’s the collectedCup function we mentioned a second ago:

collectedCup(key) {
	this.setState({ score: this.state.score + 1 });
	this.cups = this.cups.filter(cup => cup.key != key);
	this.updateMessage("Collected cup");
}

All we’re doing here is simply updating the score and then removing that cup from the list.

The final part is to display the score on the screen; let’s have a look at our updated GameStatus.jsx:

function GameStatus(props) {
	const flexStyle = {
		display: 'flex',
		position: 'absolute',
		zIndex: 1,
		margin: 20,
		justifyContent: 'center',
		alignItems: 'center',
		width: '100%'
	};
	const labelStyle = { 
		zIndex: 1,
		margin: 50
	};
	return ( 
		<div className="flex-container" style={flexStyle}>
			<label style={labelStyle}>
				Lives Remaining: {props.Lives}
			</label>
			<label style={labelStyle}>
				Score: {props.Score}
			</label>
			<label style={labelStyle}>
				{props.Message}
			</label>
		</div> 
	);
}

As you can see, we’re just displaying the score as part of the status.

In the next post, we’ll have a look at the concept of levels, and introduce a time limit.

Reference

https://www.w3schools.com/css/css3_flexbox.asp

The “LegacyFrameworkPackages” parameter is not supported by the “ResolveFrameworkReferences” task

I got this error recently while updating a project that I’m working on. It had been ported from WinForm to .Net Core 3.0, and worked fine – but suddenly I started getting errors where it claimed to not know what Form was. The output showed the error:

The “LegacyFrameworkPackages” parameter is not supported by the “ResolveFrameworkReferences” task

Unbeknownst to me, MS have changed the namespace for desktop apps; where previously your csproj might look like this:

<Project Sdk="Microsoft.NET.Sdk">
 
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>netcoreapp3.0</TargetFramework>
    <LangVersion>8.0</LangVersion>
    <NullableReferenceTypes>true</NullableReferenceTypes>
    
    <AssetTargetFallback>uap10.0.18362</AssetTargetFallback>
    <UseWindowsForms>true</UseWindowsForms>
  </PropertyGroup>

It now needs to look reference the WindowsDesktop SDK:

<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">

Creating a Car Game in React – Part 3 – Collision

In this, the third post of this series, we’re going to add collision to the game. For a full list of the code, please see here.

If you’re wondering about earlier posts, please start here.

Since we’re introducing collision, we’ll also need to introduce the age old game concept of “Lives”. The premise here is that when you crash into something, you lose a life.

The first step is to add a new state variable to hold the player’s remaining lives:

this.state = {
	playerX: 100,
	playerY: 100,
	windowWidth: 1500,
	windowHeight: 1500,
	playerMomentum: 0,
	playerRotation: 0,
	playerVelocityX: 0,
	playerVelocityY: 0,
	playerLives: 3,
	gameLoopActive: false,
	message: ""
};

If you have a look in the repository, there’s a bit of refactoring, where I’ve taken some of the setState code and separated it into logical functions. I won’t list that here.

Collision Detection

At the end of the game loop, we now have a call to check if we’ve collided with anything:

if (this.detectAnyCollision()) {
	this.PlayerDies(); 
}

The collision detection code is quite straight forward, and is based on the simplistic idea that all objects can be considered rectangles. Whilst this is not precise, it’s sufficient for our purpose:

detectAnyCollision() { 
        const halfWidth = this.spriteWidth / 2;
        const halfHeight = this.spriteHeight / 2;

        let rect1 = {x: this.state.playerX - halfWidth, y: this.state.playerY - halfHeight, 
            width: this.spriteWidth, height: this.spriteHeight}

        if (this.detectOutScreen(rect1)) {
            return true;
        }

        return this.obstacles.some(a => {
            var rect2 = {x: a.props.centreX - halfWidth, y: a.props.centreY - halfHeight, 
                width: this.spriteWidth, height: this.spriteHeight}
            
            if (this.detectCollision(rect1, rect2)) {
                return true;
            } else {
                return false;
            }
        });
}

detectCollision(rect1, rect2) {
	if (rect1.x < rect2.x + rect2.width &&
	rect1.x + rect1.width > rect2.x &&
	rect1.y < rect2.y + rect2.height &&
	rect1.y + rect1.height > rect2.y) {
		return true;
	}
	return false;
}

detectOutScreen(rect1) {
	if (rect1.x < 0 || rect1.x + rect1.width > this.state.windowWidth
	|| rect1.y < 0 || rect1.y + rect1.height > this.state.windowHeight) {
		return true;
	}
	return false;
}

The collision detection code itself was pilfered from here. As you can see, all we’re doing is translating our objects into rectangles, and then seeing if they intersect each other, or if the player has left the game area.

Quick note about forEach and some

I had originally used .forEach for the detectAnyCollision() code. Whilst it would, initially make sense to a C# programmer, in fact the Javascript version of this does exactly what it says on the tin; that is, it executes for each element, and there is no way to exit early!

Player Dies and Score

Now that we have introduced collision, we should consider what to do when it happens. The usual thing in a game is that the player either “dies”, or they lose “health”. Since this is inspired by a spectrum game, we’ll go with “dies”. You saw earlier that we introduced the concept of “lives” and, because it was a spectrum, it has to be 3!

The code to deal with the player death is:

PlayerDies() { 
	this.setState({
		playerLives: this.state.playerLives - 1,
		gameLoopActive: false
	});
	if (this.state.playerLives <= 0) {
		this.initiateNewGame();
	} else {
		this.resetCarPosition();
	}
	this.repositionPlayer();
	this.setState({ 
		gameLoopActive: true
	});
}

Just a quick reminder that this isn’t a comprehensive listing of code – please see the GitHub repository for that; however, apart from the reduction in lives, the most important thing here is the gameLoopActive code.

The idea here is that we only execute the game loop while this state variable is set; which means we can stop the game loop while we’re dealing with the player’s collision.

The change in the game loop code for this is very simple:

gameLoop() {
	if (!this.state.gameLoopActive) return;

 . . . 

Crashed Car

All well and good, but as it stands, this simply results in the car stopping when it hits a tree, and then being re-positioned. We can address this by adding a small “animation” to indicate a crash. If you have a look here, you’ll see why I’ve won several awards for my graphics*!

In order to plug this in, we’re going to change the car graphic binding:

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

So, where the crashed flag is set, we’re binding to brokenCarImg; otherwise to carImg; they are defined at the top:

import carImg from '../Assets/Car.png';
import brokenCarImg from '../Assets/Crash.png';

We also split the playerDies() function into two:

playerDying(tillDeath) {
	this.setState({
		playerCrashed: true,
		gameLoopActive: false
	});
	this.stopCar();
	setTimeout(this.playerDies.bind(this), tillDeath);
}

playerDies() { 
	this.setState({
		playerLives: this.state.playerLives - 1,
		gameLoopActive: false
	});
	if (this.state.playerLives <= 0) {
		this.initiateNewGame();
	} else {
		this.resetCarPosition();
	}
	this.repositionPlayer();
	this.setState({ 
		playerCrashed: false,
		gameLoopActive: true
	});
}

All we’re doing here is calling the first function, which effectively just changes the image and then calls the second function on a timeout. Again, don’t forget the `.bind()` when you call timeout, otherwise, you won’t be able to access `this`!

Footnotes

* I haven’t actually won any awards for graphics – I had you fooled, though!

References

https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection

https://stackoverflow.com/questions/34653612/what-does-return-keyword-mean-inside-foreach-function/34653650

https://medium.com/@benjamincherion/how-to-break-an-array-in-javascript-6d3a55bd06f6

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

Casting a C# Object From its Parent

Have you ever tried to do something akin to the following:

[Fact]
public void ConvertClassToSubClass_Converts()
{
    // Arrange
    var parentClass = new SimpleTestClass();
    parentClass.Property1 = "test";
 
    // Act
    var childClass = parentClass as SimpleTestSubClass;
 
    // Assert
    Assert.Equal("test", childClass.Property1);
}

This is a simple Xunit (failing) test. The reason is fails is because you (or I) am trying to cast a general type to a specific, and C# is complaining that this may not be possible; consequently, you will get null (or for a hard cast, you’ll get an InvalidCastException.

Okay, that makes sense. After all, parentClass could actually be a SimpleTestSubClass2 and, as a result, C# is being safe because there’s (presumably – I don’t work for MS) too many possibilities for edge cases.

This is, however, a solvable problem; there are a few ways to do it, but you can simply use reflection:

public TNewClass CastAsClass<TNewClass>() where TNewClass : class
{
 
    var newObject = Activator.CreateInstance<TNewClass>();
    var newProps = typeof(TNewClass).GetProperties();
 
    foreach (var prop in newProps)
    {
        if (!prop.CanWrite) continue;
 
        var existingPropertyInfo = typeof(TExistingClass).GetProperty(prop.Name);
        if (existingPropertyInfo == null || !existingPropertyInfo.CanRead) continue;
        var value = existingPropertyInfo.GetValue(_existingClass);
        
        prop.SetValue(newObject, value, null);
    }
 
    return newObject;
}

This code will effectively transfer any class over to any other class.

If you’d rather use an existing library, you can always use this one. It’s also Open Source on Git Hib.