├── .gitignore ├── LICENSE ├── README.md ├── gopong.png ├── index.html ├── keys.go ├── main.go ├── pong.go └── screen.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io 2 | 3 | ### OSX ### 4 | .DS_Store 5 | .AppleDouble 6 | .LSOverride 7 | 8 | # Icon must end with two \r 9 | Icon 10 | 11 | 12 | # Thumbnails 13 | ._* 14 | 15 | # Files that might appear on external disk 16 | .Spotlight-V100 17 | .Trashes 18 | 19 | # Directories potentially created on remote AFP share 20 | .AppleDB 21 | .AppleDesktop 22 | Network Trash Folder 23 | Temporary Items 24 | .apdisk 25 | 26 | 27 | ### Emacs ### 28 | # -*- mode: gitignore; -*- 29 | *~ 30 | \#*\# 31 | /.emacs.desktop 32 | /.emacs.desktop.lock 33 | *.elc 34 | auto-save-list 35 | tramp 36 | .\#* 37 | 38 | # Org-mode 39 | .org-id-locations 40 | *_archive 41 | 42 | # flymake-mode 43 | *_flymake.* 44 | 45 | # eshell files 46 | /eshell/history 47 | /eshell/lastdir 48 | 49 | # elpa packages 50 | /elpa/ 51 | 52 | # reftex files 53 | *.rel 54 | 55 | # AUCTeX auto folder 56 | /auto/ 57 | 58 | # cask packages 59 | .cask/ 60 | 61 | 62 | ### Go ### 63 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 64 | *.o 65 | *.a 66 | *.so 67 | 68 | # Folders 69 | _obj 70 | _test 71 | 72 | # Architecture specific extensions/prefixes 73 | *.[568vq] 74 | [568vq].out 75 | 76 | *.cgo1.go 77 | *.cgo2.c 78 | _cgo_defun.c 79 | _cgo_gotypes.go 80 | _cgo_export.* 81 | 82 | _testmain.go 83 | 84 | *.exe 85 | *.test 86 | *.prof 87 | 88 | 89 | ### SublimeText ### 90 | # cache files for sublime text 91 | *.tmlanguage.cache 92 | *.tmPreferences.cache 93 | *.stTheme.cache 94 | 95 | # workspace files are user-specific 96 | *.sublime-workspace 97 | 98 | # project files should be checked into the repository, unless a significant 99 | # proportion of contributors will probably not be using SublimeText 100 | # *.sublime-project 101 | 102 | # sftp configuration file 103 | sftp-config.json 104 | 105 | # Project Specific 106 | gopong.js 107 | gopong.js.map -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Claudemiro Alves Feitosa Neto 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GoPong 2 | 3 | This is an html5/canvas implementation of classic game pong. 4 | 5 | ![GoPong](https://raw.githubusercontent.com/dimiro1/gopong/master/gopong.png "GoPong") 6 | 7 | # Online version 8 | 9 | http://dimiro1.github.io/gopong/ 10 | 11 | # Compiling 12 | 13 | Just install gopherjs and build with it. 14 | 15 | ```console 16 | $ go get github.com/gopherjs/gopherjs 17 | $ gopherjs build github.com/dimiro1/gopong 18 | ``` 19 | 20 | ```html 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | ``` 30 | 31 | # Author 32 | 33 | Claudemiro Alves Feitosa Neto 34 | 35 | # LICENSE 36 | 37 | Copyright 2015 Claudemiro Alves Feitosa Neto. All rights reserved. 38 | Use of this source code is governed by a MIT-style 39 | license that can be found in the LICENSE file. 40 | 41 | -------------------------------------------------------------------------------- /gopong.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimiro1/gopong/0036b3e10c496d24718201a600172148f97a1494/gopong.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /keys.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Claudemiro Alves Feitosa Neto. All rights reserved. 2 | // Use of this source code is governed by a MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | const ( 8 | keyUp = 38 9 | keyDown = 40 10 | ) 11 | 12 | // Keys help to know which keya are pressed 13 | type Keys struct { 14 | Pressed map[int]bool 15 | } 16 | 17 | // NewKeys create a new Key 18 | func NewKeys() Keys { 19 | keys := Keys{} 20 | keys.Pressed = make(map[int]bool) 21 | 22 | return keys 23 | } 24 | 25 | // IsDown verify if the given key is pressed 26 | func (k *Keys) IsDown(key int) bool { 27 | stat, exists := k.Pressed[key] 28 | 29 | return exists && stat 30 | } 31 | 32 | // OnKeyDown Attached to OnKeyDown event 33 | func (k *Keys) OnKeyDown(key int) { 34 | k.Pressed[key] = true 35 | } 36 | 37 | // OnKeyUp Attached to OnKeyUp event 38 | func (k *Keys) OnKeyUp(key int) { 39 | k.Pressed[key] = false 40 | } 41 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Claudemiro Alves Feitosa Neto. All rights reserved. 2 | // Use of this source code is governed by a MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import "github.com/gopherjs/gopherjs/js" 8 | 9 | func main() { 10 | // Get the document 11 | document := js.Global.Get("document") 12 | 13 | // Create the canvas element 14 | canvas := document.Call("createElement", "canvas") 15 | canvas.Set("width", 300) 16 | canvas.Set("height", 200) 17 | 18 | body := document.Get("body") 19 | 20 | // append the canvas element to the html page body 21 | body.Call("appendChild", canvas) 22 | 23 | // Create the game 24 | pong := Pong{} 25 | 26 | keys := NewKeys() 27 | 28 | // A canvas Screen 29 | screen := &CanvasScreen{Canvas: canvas} 30 | 31 | // Initialize Objects 32 | pong.Load(screen) 33 | 34 | // The loop variable 35 | var loop func() 36 | 37 | // Called every time frame 38 | loop = func() { 39 | pong.Update(screen, keys) 40 | pong.Draw(screen) 41 | js.Global.Call("requestAnimationFrame", loop) 42 | } 43 | 44 | loop() 45 | 46 | // Attach keyboard events 47 | body.Call("addEventListener", "keydown", func(e js.Object) { 48 | keys.OnKeyDown(e.Get("keyCode").Int()) 49 | }) 50 | 51 | body.Call("addEventListener", "keyup", func(e js.Object) { 52 | keys.OnKeyUp(e.Get("keyCode").Int()) 53 | }) 54 | 55 | } 56 | -------------------------------------------------------------------------------- /pong.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Claudemiro Alves Feitosa Neto. All rights reserved. 2 | // Use of this source code is governed by a MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import "strconv" 8 | 9 | // Paddle is the player or the computer 10 | type Paddle struct { 11 | x int 12 | y int 13 | w int 14 | h int 15 | vel float32 16 | points int 17 | } 18 | 19 | // Paddle Up 20 | func (p *Paddle) Up() { 21 | p.y -= 1 22 | } 23 | 24 | // Paddle Down 25 | func (p *Paddle) Down() { 26 | p.y += 1 27 | } 28 | 29 | // The Ball 30 | type Ball struct { 31 | x int 32 | y int 33 | w int 34 | h int 35 | xVel int 36 | yVel int 37 | speed int 38 | } 39 | 40 | // The game object 41 | // This stores the scores, players, ball 42 | type Pong struct { 43 | player *Paddle 44 | computer *Paddle 45 | ball *Ball 46 | } 47 | 48 | // Load the game 49 | // Create the necessary objects 50 | func (p *Pong) Load(s Screen) { 51 | p.player = &Paddle{ 52 | x: 10, 53 | w: 10, 54 | h: 30, 55 | vel: 1, 56 | points: 0, 57 | } 58 | 59 | p.player.y = s.Height()/2 - p.player.h/2 60 | 61 | p.computer = &Paddle{ 62 | x: s.Width() - 20, 63 | w: 10, 64 | h: 30, 65 | vel: 1, 66 | points: 0, 67 | } 68 | 69 | p.computer.y = s.Height()/2 - p.computer.h/2 70 | 71 | p.ball = &Ball{ 72 | w: 10, 73 | h: 10, 74 | xVel: 1, 75 | yVel: -1, 76 | speed: 1, 77 | } 78 | 79 | p.reset(s) 80 | } 81 | 82 | func (p *Pong) reset(s Screen) { 83 | p.ball.x = s.Width()/2 - p.ball.w/2 84 | p.ball.y = s.Height()/2 - p.ball.h/2 85 | } 86 | 87 | // Update, Check colisions and update the game state 88 | func (p *Pong) Update(s Screen, keys Keys) { 89 | // Update Ball position 90 | p.ball.x = p.ball.x + p.ball.speed*p.ball.xVel 91 | p.ball.y = p.ball.y + p.ball.speed*p.ball.yVel 92 | 93 | // Check Colisions 94 | 95 | // Walls 96 | if (p.ball.y + p.ball.h) >= s.Height() { 97 | p.ball.yVel = -1 98 | } 99 | 100 | if p.ball.y <= 0 { 101 | p.ball.yVel = 1 102 | } 103 | 104 | // Computer 105 | if (p.ball.x+p.ball.w) >= p.computer.x && 106 | (p.ball.y+p.ball.h/2) >= p.computer.y && 107 | (p.ball.y) <= (p.computer.y+p.computer.h) { 108 | 109 | p.ball.xVel = -1 110 | } 111 | 112 | // Player 113 | if p.ball.x <= (p.player.x+p.player.w) && 114 | (p.ball.y+p.ball.h/2) >= p.player.y && 115 | p.ball.y <= (p.player.y+p.player.h) { 116 | 117 | p.ball.xVel = 1 118 | } 119 | 120 | // Dumb Computer AI 121 | // Middle of the screen 122 | if p.ball.x > s.Width()/2 { 123 | if p.ball.y < (p.computer.y + p.ball.h) { 124 | if p.computer.y >= 0 { 125 | p.computer.Up() 126 | } 127 | } else { 128 | if p.computer.y <= s.Height()-p.computer.h { 129 | p.computer.Down() 130 | } 131 | } 132 | } 133 | 134 | // Points 135 | 136 | if p.ball.x > p.computer.x { 137 | p.player.points++ 138 | 139 | p.reset(s) 140 | } 141 | 142 | if p.ball.x <= 0 { 143 | p.computer.points++ 144 | 145 | p.reset(s) 146 | } 147 | 148 | // Keyboard 149 | if keys.IsDown(keyUp) { 150 | if p.player.y >= 0 { 151 | p.player.Up() 152 | } 153 | } 154 | 155 | if keys.IsDown(keyDown) { 156 | if p.player.y <= s.Height()-p.player.h { 157 | p.player.Down() 158 | } 159 | } 160 | } 161 | 162 | // Draw the objects on the screen 163 | func (p *Pong) Draw(screen Screen) { 164 | 165 | black := Color{0, 0, 0} 166 | white := Color{255, 255, 255} 167 | green := Color{0, 200, 0} 168 | red := Color{200, 0, 0} 169 | 170 | // Background 171 | screen.DrawRect(0, 0, screen.Width(), screen.Height(), black) 172 | 173 | // Player 174 | screen.DrawRect(p.player.x, p.player.y, p.player.w, p.player.h, white) 175 | 176 | // Computer 177 | screen.DrawRect(p.computer.x, p.computer.y, p.computer.w, p.computer.h, red) 178 | 179 | // Ball 180 | screen.DrawRect(p.ball.x, p.ball.y, p.ball.w, p.ball.h, green) 181 | 182 | // Points 183 | screen.DrawText(strconv.Itoa(p.player.points), screen.Width()/2-50, 20, white) 184 | screen.DrawText(strconv.Itoa(p.computer.points), screen.Width()/2+50, 20, white) 185 | } 186 | -------------------------------------------------------------------------------- /screen.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Claudemiro Alves Feitosa Neto. All rights reserved. 2 | // Use of this source code is governed by a MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | 10 | "github.com/gopherjs/gopherjs/js" 11 | ) 12 | 13 | // A color object 14 | type Color struct { 15 | R int // Red 16 | G int // Green 17 | B int // Blue 18 | } 19 | 20 | // The Screen interface 21 | // It hides the internal implementation of the screen drawing 22 | type Screen interface { 23 | // Draw a rectangle on the screen 24 | DrawRect(x, y, w, h int, color Color) 25 | // Draw the text at the position 26 | DrawText(text string, x, y int, color Color) 27 | // The Screen width 28 | Width() int 29 | // The screen Height 30 | Height() int 31 | } 32 | 33 | // A HTML5 Canvas Screen implementation 34 | type CanvasScreen struct { 35 | Canvas *js.Object // Javascript canvas Object 36 | } 37 | 38 | // HTML5 Canvas implementation of a DrawText 39 | func (s *CanvasScreen) DrawText(text string, x, y int, color Color) { 40 | ctx := s.Canvas.Call("getContext", "2d") 41 | 42 | ctx.Set("fillStyle", fmt.Sprintf("rgb(%d, %d, %d)", color.R, color.G, color.B)) 43 | ctx.Call("fillText", text, x, y) 44 | } 45 | 46 | // HTML5 Canvas implementation of a DrawRect 47 | func (s *CanvasScreen) DrawRect(x, y, w, h int, color Color) { 48 | ctx := s.Canvas.Call("getContext", "2d") 49 | 50 | ctx.Set("fillStyle", fmt.Sprintf("rgb(%d, %d, %d)", color.R, color.G, color.B)) 51 | ctx.Call("fillRect", x, y, w, h) 52 | } 53 | 54 | // Canvas Width 55 | func (s *CanvasScreen) Width() int { 56 | return s.Canvas.Get("width").Int() 57 | } 58 | 59 | // Canvas Height 60 | func (s *CanvasScreen) Height() int { 61 | return s.Canvas.Get("height").Int() 62 | } 63 | --------------------------------------------------------------------------------