Skip to content

Commit 168d1c6

Browse files
initial commit
0 parents  commit 168d1c6

34 files changed

+5034
-0
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
test/*
2+
3+
*.txt
4+
5+
.DS_Store

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
## Multiplayer top down shooter
2+
3+
- Automatic local network searching for multiplayer
4+
- Windfield for collision detection
5+
6+
## Useful links
7+
8+
### Sockets
9+
10+
- https://tst2005.github.io/lua-socket/udp.html - Network support for the Lua language documentation
11+
- https://github.com/diegonehab/luasocket
12+
- https://love2d.org/wiki/Tutorial:Networking_with_UDP-TheServer
13+
- https://love2d.org/wiki/Tutorial:Networking_with_UDP-TheClient
14+
- http://www.love2d.org/forums/viewtopic.php?f=4&t=86979 - [SOLVED] Luasocket UDP broadcast
15+
- https://en.wikipedia.org/wiki/Multicast_address
16+
- https://code.activestate.com/recipes/578802-send-messages-between-computers/ (UDP python)
17+
- http://w3.impa.br/~diego/software/luasocket/introduction.html
18+
19+
### Windfield
20+
21+
- https://github.com/a327ex/windfield
22+
- https://love2d.org/wiki/Body
23+
- https://box2d.org/documentation/md__d_1__git_hub_box2d_docs_collision.html

game/bullet.lua

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
local function spawn(server, player)
2+
local bullet = {}
3+
server.bulletNum = server.bulletNum + 1
4+
bullet.id = server.bulletNum
5+
bullet.playerID = player.id
6+
bullet.speed = 500
7+
bullet.dead = false
8+
9+
local bulletAngleIndex = server.angleIndex - 8
10+
if bulletAngleIndex < 0 then
11+
bulletAngleIndex = server.anglesMax - 8
12+
end
13+
bullet.direction = server.angles[bulletAngleIndex]
14+
15+
bullet.x = player.x + math.cos(bullet.direction) * 40
16+
bullet.y = player.y + math.sin(bullet.direction) * 40
17+
18+
if player.direction == 'left' then
19+
bullet.x = bullet.x - 10
20+
elseif player.direction == 'right' then
21+
bullet.x = bullet.x + 10
22+
elseif player.direction == 'up' then
23+
bullet.y = bullet.y - 10
24+
elseif player.direction == 'down' then
25+
bullet.y = bullet.y + 10
26+
end
27+
return bullet
28+
end
29+
30+
local function move(server, bullet, collider, dt)
31+
collider = collider or false
32+
bullet.x = bullet.x + (math.cos( bullet.direction ) * bullet.speed * dt)
33+
bullet.y = bullet.y + (math.sin( bullet.direction ) * bullet.speed * dt)
34+
if collider then
35+
if not server.bulletCollider[bullet.id] then
36+
server.bulletCollider[bullet.id] = server.world:newCircleCollider(bullet.x, bullet.y, 15)
37+
server.bulletCollider[bullet.id]:setCollisionClass('bullet')
38+
else
39+
server.bulletCollider[bullet.id]:setX(bullet.x)
40+
server.bulletCollider[bullet.id]:setY(bullet.y)
41+
end
42+
if server.bulletCollider[bullet.id]:enter('zombie') then
43+
-- print('collision bz! ' , bullet.id)
44+
local collision_data = server.bulletCollider[bullet.id]:getEnterCollisionData('zombie')
45+
local zombieHit = collision_data.collider:getObject()
46+
-- print('collision with : ', zombieHit.id)
47+
local playerScore = server.players[bullet.playerID].score
48+
server.players[bullet.playerID].score = playerScore + 1
49+
zombieHit.dead = true
50+
bullet.dead = true
51+
end
52+
53+
if server.bulletCollider[bullet.id]:enter('player') then
54+
-- print('collision bp! ' , bullet.id)
55+
local collision_data = server.bulletCollider[bullet.id]:getEnterCollisionData('player')
56+
local playerHit = collision_data.collider:getObject()
57+
-- print('collision with : ', playerHit.id)
58+
if playerHit.id ~= bullet.playerID then
59+
bullet.dead = true
60+
end
61+
end
62+
end
63+
end
64+
65+
local function cleanup(server)
66+
for i=#server.bullets, 1, -1 do
67+
local b = server.bullets[i]
68+
if b.x < 0 or b.y < 0 or b.x > love.graphics.getWidth() or b.y > love.graphics.getHeight() then
69+
b.dead = true
70+
end
71+
if b.dead == true then
72+
table.remove(server.bullets, i)
73+
if server.bulletCollider[b.id] then server.bulletCollider[b.id]:destroy() end
74+
server.players[b.playerID].accuracy = (server.players[b.playerID].score/server.players[b.playerID].bulletsFired) * 100
75+
end
76+
end
77+
end
78+
79+
return {
80+
spawn = spawn,
81+
move = move,
82+
cleanup = cleanup
83+
}

game/client/bullet.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../bullet.lua

game/client/game.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../game.lua

game/client/libraries

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../libraries

game/client/main.lua

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
-- package.path = package.path .. ";../?.lua"
2+
-- package.path = package.path .. ";../?/init.lua"
3+
4+
local game = require "game"
5+
local zombie = require "zombie"
6+
local player = require "player"
7+
8+
function love.load()
9+
love.window.setMode(800, 600)
10+
GameClient = game.newClient(22122)
11+
love.window.setTitle( "Client")
12+
13+
Sprites = {}
14+
Sprites.background = love.graphics.newImage('sprites/background.png')
15+
Sprites.bullet = love.graphics.newImage('sprites/bullet.png')
16+
Sprites.player = love.graphics.newImage('sprites/player1.png')
17+
Sprites.extra = love.graphics.newImage('sprites/ext.png')
18+
Sprites.zombie = love.graphics.newImage('sprites/zombie.png')
19+
20+
Fonts = {}
21+
Fonts.xs = love.graphics.newFont(15)
22+
Fonts.s = love.graphics.newFont(20)
23+
Fonts.m = love.graphics.newFont(25)
24+
Fonts.l = love.graphics.newFont(30)
25+
26+
-- setup a local player for offline play
27+
player.reset(GameClient.player)
28+
GameClient.player.name = 'Player_1'
29+
GameClient.player.id = 'id'
30+
GameClient.players['id'] = GameClient.player
31+
end
32+
33+
34+
function love.update(dt)
35+
GameClient:update(dt)
36+
end
37+
38+
function love.draw()
39+
40+
-- uncomment for debug, also comment background then
41+
-- GameClient.world:draw()
42+
43+
-- drawing shapes first
44+
love.graphics.setColor(1, 1, 1, 1) -- white
45+
46+
-- background
47+
love.graphics.draw(Sprites.background, 0, 0)
48+
49+
-- all players
50+
if GameClient.currentGameState ~= GameClient.states.GAME_END then
51+
for id, playerObj in pairs(GameClient.players) do
52+
local spriteObj = Sprites.extra
53+
local angle = playerObj.angle
54+
local x = playerObj.x
55+
local y = playerObj.y
56+
if playerObj.id == GameClient.player.id then
57+
spriteObj = Sprites.player
58+
angle = GameClient.player.angle
59+
x = GameClient.player.x
60+
y = GameClient.player.y
61+
end
62+
love.graphics.draw(spriteObj,x, y, angle, 2, 2, spriteObj:getWidth()/2, spriteObj:getHeight()/2)
63+
end
64+
end
65+
66+
-- extra
67+
for i,z in ipairs(GameClient.zombies) do
68+
love.graphics.draw(Sprites.zombie, z.x, z.y, zombie.playerAngle(z), nil, nil, Sprites.zombie:getWidth()/2, Sprites.zombie:getHeight()/2)
69+
end
70+
71+
for i,b in ipairs(GameClient.bullets) do
72+
love.graphics.draw(Sprites.bullet, b.x, b.y, nil, 0.5, 0.5, Sprites.bullet:getWidth()/2, Sprites.bullet:getHeight()/2)
73+
end
74+
------------------------------------------------------------------------
75+
-- drawing text now
76+
77+
love.graphics.setColor(0, 0, 0, 1) -- black
78+
79+
-- player information
80+
if GameClient.client then
81+
love.graphics.printf("Name: " .. GameClient.player.name, Fonts.xs, 10, 10, love.graphics.getWidth(), "left")
82+
love.graphics.printf("RTT: " .. GameClient.client:getRoundTripTime(), Fonts.xs, -10, 10, love.graphics.getWidth(), "right")
83+
love.graphics.printf("Server: " .. GameClient.client:getAddress(), Fonts.xs, -10, 30, love.graphics.getWidth(), "right")
84+
end
85+
86+
-- text according to game states
87+
if GameClient.currentGameState == GameClient.states.CLIENT_PLAY then
88+
love.graphics.printf("Finding server ...", Fonts.l, 0, 50, love.graphics.getWidth(), "center")
89+
end
90+
if GameClient.currentGameState == GameClient.states.INIT then
91+
love.graphics.printf("Press spacebar to begin!", Fonts.l, 0, 50, love.graphics.getWidth(), "center")
92+
end
93+
if GameClient.currentGameState == GameClient.states.WAITING then
94+
love.graphics.printf("Ready! Waiting for other players", Fonts.l, 0, 50, love.graphics.getWidth(), "center")
95+
end
96+
if GameClient.player.score and
97+
(GameClient.currentGameState == GameClient.states.READY
98+
or GameClient.currentGameState == GameClient.states.CLIENT_PLAY) then
99+
love.graphics.printf("Score: " .. GameClient.player.score, Fonts.l, 10, love.graphics.getHeight()-100, love.graphics.getWidth(), "center")
100+
love.graphics.printf("Bullets: " .. GameClient.player.bulletsFired, Fonts.xs, 10, love.graphics.getHeight()-50, love.graphics.getWidth(), "left")
101+
love.graphics.printf("Accuracy: " .. string.format("%.2f %%", GameClient.player.accuracy), Fonts.xs, 10, love.graphics.getHeight()-30, love.graphics.getWidth(), "left")
102+
end
103+
if GameClient.player.score and GameClient.currentGameState == GameClient.states.GAME_END then
104+
love.graphics.printf("Game over! Press spacebar to restart!", Fonts.l, 0, 50, love.graphics.getWidth(), "center")
105+
love.graphics.printf("Scores: ", Fonts.m, 20, love.graphics.getHeight()-250, love.graphics.getWidth(), "left")
106+
local height = 200
107+
local zombiesKilled = 0
108+
local sortedByScore = {}
109+
for id, playerObj in pairs(GameClient.playersClientCopy) do
110+
zombiesKilled = zombiesKilled + playerObj.score
111+
table.insert(sortedByScore, {id, playerObj})
112+
end
113+
table.sort(sortedByScore, function(a, b) return a[2].score > b[2].score end)
114+
for _, v in pairs(sortedByScore) do
115+
local playerObj = v[2]
116+
if playerObj.id == GameClient.player.id then love.graphics.setColor(1, 0, 0, 1) end
117+
love.graphics.printf(playerObj.name .. " :: Zombies killed: " .. playerObj.score .. ", Accuracy: " .. string.format("%.2f %%", playerObj.accuracy), Fonts.s ,20, love.graphics.getHeight()-height, love.graphics.getWidth(), "left")
118+
love.graphics.setColor(0, 0, 0, 1)
119+
height = height - 30
120+
end
121+
love.graphics.printf("Total zombies killed : " .. zombiesKilled, Fonts.m, 0, 100, love.graphics.getWidth(), "center")
122+
end
123+
if GameClient.currentGameState == GameClient.states.SERVER_DISCONNECT then
124+
love.graphics.printf("Disconnected from server.. Game will close soon!", Fonts.l, 0, 50, love.graphics.getWidth(), "center")
125+
end
126+
end
127+
128+
function love.keypressed(key)
129+
if key == "space" then
130+
if GameClient.client then
131+
GameClient.client:send("input", {
132+
timestamp = love.timer.getTime(),
133+
})
134+
else
135+
GameClient:resetGame()
136+
GameClient.currentGameState = GameClient.states.CLIENT_PLAY
137+
end
138+
end
139+
end
140+
141+
function love.keyreleased(key)
142+
if key == "w" or key == "a" or key == "s" or key == "d" then
143+
GameClient.player.direction = 'neutral'
144+
end
145+
end
146+
147+
function love.quit()
148+
print("Thanks for playing!")
149+
if GameClient.client then
150+
GameClient.client:disconnectNow()
151+
end
152+
end

game/client/player.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../player.lua

game/client/sprites/background.png

99.1 KB
Loading
35.2 KB
Loading

0 commit comments

Comments
 (0)