Skip to content

Commit

Permalink
Merge pull request #15 from devshareacademy/connect-four
Browse files Browse the repository at this point in the history
Connect four game prototype
  • Loading branch information
scottwestover authored Sep 9, 2024
2 parents 958b86c + 065bd7c commit 00262af
Show file tree
Hide file tree
Showing 14 changed files with 1,452 additions and 0 deletions.
4 changes: 4 additions & 0 deletions games/connect-four/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/dist
/node_modules
yarn-error.log
.DS_Store
13 changes: 13 additions & 0 deletions games/connect-four/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"eslint.format.enable": true,
"eslint.options": {
"overrideConfigFile": "config/.eslintrc"
},
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"cSpell.words": [
"devshareacademy"
]
}
50 changes: 50 additions & 0 deletions games/connect-four/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Phaser 3 TypeScript - Connect Four

A basic Phaser 3 TypeScript prototype of the game Connect Four.

You can see a live demo of the example here: [Phaser 3 Connect Four](https://devshareacademy.github.io/phaser-3-typescript-games-and-examples/games/connect-four/index.html)

## Local Development

### Requirements

[Node.js](https://nodejs.org) and [Yarn](https://yarnpkg.com/) are required to install dependencies and run scripts via `yarn`.

[Vite](https://vitejs.dev/) is required to bundle and serve the web application. This is included as part of the projects dev dependencies.

### Available Commands

| Command | Description |
|---------|-------------|
| `yarn install --frozen-lockfile` | Install project dependencies |
| `yarn start` | Build project and open web server running project |
| `yarn build` | Builds code bundle for production |
| `yarn lint` | Uses ESLint to lint code |

### Writing Code

After cloning the repo, run `yarn install --frozen-lockfile` from your project directory. Then, you can start the local development
server by running `yarn start`.

After starting the development server with `yarn start`, you can edit any files in the `src` folder
and parcel will automatically recompile and reload your server (available at `http://localhost:8080`
by default).

### Deploying Code

After you run the `yarn build` command, your code will be built into a single bundle located at
`dist/*` along with any other assets you project depended.

If you put the contents of the `dist` folder in a publicly-accessible location (say something like `http://myserver.com`),
you should be able to open `http://myserver.com/index.html` and play your game.

### Static Assets

Any static assets like images or audio files should be placed in the `public` folder. It'll then be served at `http://localhost:8080/path-to-file-your-file/file-name.file-type`.

## Ideas for improvement

* add support for mobile
* add title & game over screens
* add cpu
* add animations
9 changes: 9 additions & 0 deletions games/connect-four/config/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"root": true,
"extends": "@devshareacademy/eslint-config",
"parserOptions": {
"project": "./tsconfig.json"
},
"rules": {},
"ignorePatterns": ["node_modules", "dist"]
}
12 changes: 12 additions & 0 deletions games/connect-four/config/vite.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { defineConfig } from 'vite';

export default defineConfig({
base: "./",
build: {
rollupOptions: {
output: {
entryFileNames: 'assets/js/[name]-[hash].js',
},
},
},
});
27 changes: 27 additions & 0 deletions games/connect-four/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Basic Phaser 3 Example Template</title>
<style>
html,
body,
.container {
margin: 0px;
height: 100vh;
width: 100vw;
overflow: hidden;
background: #d7d7d7;
display: flex;
flex-direction: column;
align-items: center;
}
</style>
</head>
<body>
<div class="container" id="game-container">
<h1>Phaser 3 - Connect Four</h1>
</div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
41 changes: 41 additions & 0 deletions games/connect-four/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"name": "@devshareacademy/phaser-3-typescript-game-template",
"version": "1.0.0",
"description": "A basic Phaser 3 Typescript project template that uses Vite.",
"scripts": {
"start": "vite --config config/vite.config.js",
"build": "tsc && vite build --config config/vite.config.js",
"serve": "vite preview --config config/vite.config.js",
"lint": "eslint ./src --ext .ts,.tsx --config ./config/.eslintrc"
},
"author": "scottwestover",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/devshareacademy/phaser-3-typescript-games-and-examples.git"
},
"homepage": "https://github.com/devshareacademy/phaser-3-typescript-games-and-examples",
"devDependencies": {
"@devshareacademy/eslint-config": "0.0.16",
"@devshareacademy/prettier-config": "0.0.4",
"@devshareacademy/tsconfig": "0.0.3",
"@typescript-eslint/eslint-plugin": "5.22.0",
"@typescript-eslint/parser": "5.22.0",
"eslint": "8.14.0",
"eslint-config-prettier": "8.5.0",
"eslint-plugin-prettier": "4.0.0",
"prettier": "2.6.2",
"typescript": "4.6.4",
"vite": "2.9.13"
},
"dependencies": {
"@devshareacademy/connect-four": "0.0.5",
"phaser": "3.55.2"
},
"resolutions": {},
"prettier": "@devshareacademy/prettier-config",
"volta": {
"node": "16.15.0",
"yarn": "1.22.11"
}
}
14 changes: 14 additions & 0 deletions games/connect-four/project-task.todo
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
☐ download project assets
☐ update game config
☐ install connect four npm package
☐ load in assets
☐ create board layout
☐ handle player input
☐ update text in ui
☐ handle hover events
☐ handle click events
☐ add game piece
☐ handle game over
☐ draw winner message box
☐ update text in ui
☐ reset game
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
127 changes: 127 additions & 0 deletions games/connect-four/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import * as Phaser from 'phaser';
import { ConnectFour } from '@devshareacademy/connect-four';
import { Player } from '@devshareacademy/connect-four/dist/types';

const ASSET_KEY = 'spritesheet';
const SCALE_SIZE = 2;
const FRAME_SIZE = 32;
const SCALED_FRAME_SIZE = SCALE_SIZE * FRAME_SIZE;
const GAME_HEIGHT = SCALED_FRAME_SIZE * 6;
const GAME_WIDTH = SCALED_FRAME_SIZE * 7;

class Game extends Phaser.Scene {
private connectFour!: ConnectFour;

constructor() {
super({ key: 'Game' });
}

public init(): void {
this.connectFour = new ConnectFour();
}

public preload(): void {
// load in data
this.load.spritesheet(ASSET_KEY, 'assets/images/connect-four.png', {
frameWidth: 32,
frameHeight: 32,
});
}

public create(): void {
// Create game objects
this.createBoard();
this.createInputColumns();
}

private createBoard(): void {
for (let i = 0; i < this.connectFour.board[0].length; i++) {
for (let j = 0; j < this.connectFour.board.length; j++) {
const x = i * SCALED_FRAME_SIZE;
const y = j * SCALED_FRAME_SIZE;
this.add.image(x, y, ASSET_KEY, 2).setOrigin(0).setScale(SCALE_SIZE).setDepth(2);
}
}
}

private createInputColumns(): void {
const columnIndexKey = 'columnIndex';

// create the columns for the game and make them interactive
for (let i = 0; i < this.connectFour.board[0].length; i++) {
const x = i * SCALED_FRAME_SIZE;
const rect = this.add.rectangle(x, 0, SCALED_FRAME_SIZE, GAME_HEIGHT, 0xffff00).setOrigin(0).setInteractive();
rect.setAlpha(0.01);
rect.setData(columnIndexKey, i);
rect.on(Phaser.Input.Events.POINTER_OVER as string, () => {
if (this.connectFour.isGameOver) {
return;
}
rect.setAlpha(0.2);
});
rect.on(Phaser.Input.Events.POINTER_OUT as string, () => {
rect.setAlpha(0.01);
});
rect.on(Phaser.Input.Events.POINTER_DOWN as string, () => {
if (this.connectFour.isGameOver) {
return;
}

const currentPlayer = this.connectFour.playersTurn;
const coordinate = this.connectFour.makeMove(rect.getData(columnIndexKey) as number);
this.addGamePiece(coordinate.row, coordinate.col, currentPlayer);
});
}
}

private addGamePiece(row: number, col: number, player: string): void {
const gamePieceFrame = player === Player.ONE ? 0 : 1;
const x = col * SCALED_FRAME_SIZE;
const y = row * SCALED_FRAME_SIZE;
this.add.image(x, y, ASSET_KEY, gamePieceFrame).setOrigin(0).setScale(SCALE_SIZE).setDepth(1);
this.checkForGameOver();
}

private checkForGameOver(): void {
if (!this.connectFour.isGameOver) {
return;
}

this.add
.rectangle(20, GAME_HEIGHT / 3, GAME_WIDTH - 40, GAME_HEIGHT / 4, 0x000000)
.setOrigin(0)
.setDepth(4)
.setInteractive()
.once(Phaser.Input.Events.POINTER_DOWN as string, () => {
this.scene.restart();
});

let winText = 'Draw';
if (this.connectFour.gameWinner) {
winText = `Player ${this.connectFour.gameWinner} Wins!`;
}

this.add
.text(GAME_WIDTH / 2, GAME_HEIGHT / 3 + 30, winText, { fontSize: '32px' })
.setOrigin(0.5)
.setDepth(5);
this.add
.text(GAME_WIDTH / 2, GAME_HEIGHT / 2 + 15, 'Click here to play again!')
.setOrigin(0.5)
.setDepth(5);
}
}

const gameConfig: Phaser.Types.Core.GameConfig = {
type: Phaser.CANVAS,
pixelArt: true,
scale: {
parent: 'game-container',
width: GAME_WIDTH,
height: GAME_HEIGHT,
},
backgroundColor: '#5c5b5b',
scene: [Game],
};

const game = new Phaser.Game(gameConfig);
17 changes: 17 additions & 0 deletions games/connect-four/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"extends": "@devshareacademy/tsconfig/tsconfig.json",
"compilerOptions": {
"outDir": "dist",
"typeRoots": [
"node_modules/@types"
]
},
"include": [
"**/*.ts"
],
"ts-node": {
"compilerOptions": {
"module": "commonjs"
}
}
}
Loading

0 comments on commit 00262af

Please sign in to comment.