Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion README.md
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1 +1,37 @@
# FinalProject
# Procedural Pokemon
no memes allowed


## Milestone 2 Accomplishments
### David
- Made the game multiplayer. Networking for proceduralism. (this is like a 4/5 on the difficulty scale)
- Slick differential updates to sync game state
- Fixed all (I think) server-side race conditions and bugs
- Implemented randomized behavior based off of a global seed variables defined by the user, so instaces of our randomized pokemon game are standardized for each player on the network
- Refactors

### Joseph
- Updated sprites for the character, terrtain, and Pokemon
- Implemented biomes - world is split into four quadrants (grass, desert, water, snow), and the sprite textures now have color to better display the distinct biomes
- Expanded Tile data structure to hold pokemon information, as well as whether or not certain parts of the terrain are traversable
- Completed random pokemon spawn algorithm to spawn specific pokemon types in each biome. For example, Charmanders will not spawn in the desert, Bulbasaur's will not spawn in the water, etc.
- Changed Sprite class so it is able to handle sprites not just of size 16x16
-Files changed: Tile.js, World.js, RenderEngine.js, App.js, Sprite.js

#### All tasks specified in the milestone (updated doc we pinged to rachel and later forwarded to Adam) were completed

## Milestone 1 Accomplishments

### David
- Configured infrastructure and set up the project.
- Implemented sprite importing and rendering.
- Created a base world using the current sprite set.
- Implemented player.js and enabled player movement throughout the scene.
- Implemented the viewport so we only see a certain poprtion of the world.
- File changed: Made changes in all files (see commits).

### Joseph
- Implemented Tile logic for use by the Grid. Tiles will be used to later determine which parts of the world belong to which biome, as well as which parts of the world are traversable, or will hold wild pokemon, etc. Currently used to holds symbols that tells the render engine what to render.
- Implemented render engine to render information in a tile. For now just the ability to render a single sprite to the canvas. David expanded this functionality to create the vanilla world you see.
- Developed logic for randomly spawning 'pokemon' throughout the world. Each index in the grid currently has some percentage change of spawning a pokemon. Currently the pokemon are represented by a symbol.
- Files changed: Tile.js, Grid.js, RenderEngine.js, App.js
1 change: 1 addition & 0 deletions assets/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Assets that are used will be housed here
Binary file added assets/biomes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/biomes.psd
Binary file not shown.
Binary file added assets/overworld.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/pepe.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/player.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/player2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/pokemon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/sprites.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file added css/index.css
Empty file.
35 changes: 35 additions & 0 deletions deploy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
PROJ_DIR=~/workspace/procedural-pokemon
BUILD_DIR=$PROJ_DIR/build
DEPLOY_DIR=$PROJ_DIR/../procedural_pokemon_build
set -o errexit

printf "Building...\n"
git checkout master 1>/dev/null 2>/dev/null
git pull origin master 1>/dev/null 2>/dev/null
npm run build > /dev/null

printf "Creating deploy environment...\n"
if [ -d $DEPLOY_DIR ]; then
rm -rf $DEPLOY_DIR > /dev/null
printf "Deploy directory already exists, removing...\n"
fi

mkdir -p $DEPLOY_DIR
cp -R $BUILD_DIR/* $DEPLOY_DIR
cp -R $PROJ_DIR/assets $DEPLOY_DIR
cp $PROJ_DIR/index.html $DEPLOY_DIR
cd $DEPLOY_DIR

printf "Deploying...\n"
git init > /dev/null
git remote add origin [email protected]:davlia/procedural-pokemon.git > /dev/null
git checkout -b gh-pages 1>/dev/null 2>/dev/null
git add -A > /dev/null
git commit -am "deploying" > /dev/null
git push -f origin gh-pages 1>/dev/null 2>/dev/null

printf "Cleaning up...\n"
rm -rf $BUILD_DIR
rm -rf $DEPLOY_DIR

printf "Success!\n"
10 changes: 10 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<title>Procedural Pokemon</title>
<link rel="stylesheet" href="./css/index.css">
</head>
<body>
<script src="bundle.js"></script>
</body>
</html>
30 changes: 30 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"scripts": {
"start": "webpack-dev-server --hot --inline",
"build": "webpack",
"deploy": "./deploy.sh"
},
"gh-pages-deploy": {
"prep": [
"build"
],
"noprompt": true
},
"dependencies": {
"dat-gui": "^0.5.0",
"express": "^4.15.2",
"gl-matrix": "^2.3.2",
"stats-js": "^1.0.0-alpha1"
},
"devDependencies": {
"babel-core": "^6.18.2",
"babel-loader": "^6.2.8",
"babel-preset-es2015": "^6.18.0",
"colors": "^1.1.2",
"gh-pages-deploy": "^0.4.2",
"simple-git": "^1.65.0",
"webpack": "1.14.0",
"webpack-dev-server": "^1.16.3",
"webpack-glsl-loader": "^1.0.1"
}
}
2 changes: 2 additions & 0 deletions server/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
all:
go run *.go
33 changes: 33 additions & 0 deletions server/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package main

import "github.com/gorilla/websocket"

// Client encapsulates all player connection contexts
type Client struct {
Conn *websocket.Conn
ID int32
}

// NewClient creates a new client
func NewClient(conn *websocket.Conn, id int32) *Client {
c := &Client{
Conn: conn,
ID: id,
}
return c
}

// ReadJSON forwards the ReadJSON call
func (C *Client) ReadJSON(v interface{}) error {
return C.Conn.ReadJSON(v)
}

// WriteJSON forwards the WriteJSON call
func (C *Client) WriteJSON(v interface{}) error {
return C.Conn.WriteJSON(v)
}

// Close forwards the Close call
func (C *Client) Close() error {
return C.Conn.Close()
}
116 changes: 116 additions & 0 deletions server/controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package main

import (
"log"
"math/rand"

"github.com/gorilla/websocket"
)

// Controller handles all ws connection events and is the driver module
type Controller struct {
ReceiveChan chan InboundMessage
SendChan chan OutboundMessage
Clients map[int32]*Client
Game Game
}

// NewController creates a new controller
func NewController() Controller {
g := Game{
World: World{
Size: 100,
Seed: 0,
Players: []Player{},
},
}
c := Controller{
ReceiveChan: make(chan InboundMessage, 128),
SendChan: make(chan OutboundMessage, 128),
Clients: make(map[int32]*Client),
Game: g,
}
return c
}

func (C *Controller) run() {
go C.handleInboundMessages()
go C.handleOutboundMessages()
}

func (C *Controller) handleInboundMessages() {
for {
msg := <-C.ReceiveChan
switch msg.Type {
case "init":
C.handleInit(msg)
case "sync":
C.handleSync(msg)
default:
log.Printf("message unhandled: %+v\n", msg)
}
}
}

func (C *Controller) sendMessage(t string, data Data, id int32) {
send := OutboundMessage{
Type: t,
Data: data,
Receiver: id,
}
C.SendChan <- send
}

func (C *Controller) broadcastMessage(t string, data Data, sender int32) {
for id := range C.Clients {
if id == sender {
continue
}
C.sendMessage(t, data, id)
}
}

func (C *Controller) handleOutboundMessages() {
for {
msg := <-C.SendChan
client, ok := C.Clients[msg.Receiver]
if !ok {
log.Printf("error: could not find connection by id\n")
continue
}
client.WriteJSON(msg)
}
}

// AddConn adds connections to be tracked and listened to
func (C *Controller) AddConn(conn *websocket.Conn) {
id := C.nextID()
client := NewClient(conn, id)
C.Clients[id] = client
go C.readFromClient(client)
}

func (C *Controller) readFromClient(client *Client) {
for {
var msg InboundMessage
err := client.ReadJSON(&msg)
if err != nil {
log.Printf("Connection closed by %d\n", client.ID)
C.handleDisconnect(client.ID)
return
}
// TODO: this is sort of hacky IMO? should refactor in future
msg.Sender = client.ID
C.ReceiveChan <- msg
}
}

func (C *Controller) nextID() int32 {
// TODO: do something else here that doesn't put your 4 years of higher education to fucking shame
for {
id := rand.Int31()
if _, ok := C.Clients[id]; !ok {
return id
}
}
}
6 changes: 6 additions & 0 deletions server/gameinstance.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package main

// GameInstance encapsulates game instance data
type GameInstance struct {
Players []Player
}
45 changes: 45 additions & 0 deletions server/handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package main

func (C *Controller) handleInit(msg InboundMessage) {
p := Player{
Pos: Point{X: 10, Y: 10},
ID: msg.Sender,
}
players := C.Game.World.Players
players = append(players, p)
C.Game.World.Players = players
d := Data{
Message: "alrighty, here you go",
Game: C.Game,
}

C.sendMessage("init", d, msg.Sender)
C.broadcastMessage("sync", d, msg.Sender)
}

func (C *Controller) handleSync(msg InboundMessage) {
C.Game = msg.Data.Game
d := Data{
Message: "catch up plz",
Game: C.Game,
}
C.broadcastMessage("sync", d, msg.Sender)
}

func (C *Controller) handleDisconnect(id int32) {
players := C.Game.World.Players
index := -1
for i, p := range players {
if p.ID == id {
index = i
}
}
players = append(players[:index], players[index+1:]...)
C.Game.World.Players = players
delete(C.Clients, id)
d := Data{
Message: "catch up plz",
Game: C.Game,
}
C.broadcastMessage("sync", d, -1)
}
67 changes: 67 additions & 0 deletions server/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package main

import (
"fmt"
"log"
"net/http"
"os"
"time"

"github.com/gorilla/mux"
"github.com/gorilla/websocket"
)

var (
addr = ":8000"
upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
return true
},
}
c = NewController()
)

func main() {
env := os.Getenv("environment")

go c.run()
r := mux.NewRouter()

r.HandleFunc("/health", health)
r.HandleFunc("/play", handleConnection)

s := http.Server{
Handler: r,
Addr: addr,
WriteTimeout: 15 * time.Second,
ReadTimeout: 15 * time.Second,
}
log.Printf("Listening and serving on %s\n", addr)
if env == "production" {
log.Fatal(s.ListenAndServeTLS("server.crt", "server.key"))
} else {
log.Fatal(s.ListenAndServe())
}
}

// health reports 200 if services is up and running
func health(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "we healthy bois")
}

// handleConnection handles websocket requests from client
func handleConnection(w http.ResponseWriter, r *http.Request) {
if r.Method != "GET" {
http.Error(w, "Method not allowed", 405)
return
}

conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println(err)
return
}
c.AddConn(conn)
}
Loading