Skip to content

Commit 90e8899

Browse files
committed
content update
1 parent 9a36eb2 commit 90e8899

20 files changed

+438
-17
lines changed

.gitattributes

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Common settings that generally should always be used with your language specific settings
2+
3+
# Auto detect text files and perform LF normalization
4+
* text=auto
5+
6+
#
7+
# The above will handle all files NOT mentioned below
8+
#
9+
10+
# Documents
11+
*.bibtex text diff=bibtex
12+
*.doc diff=astextplain
13+
*.DOC diff=astextplain
14+
*.docx diff=astextplain
15+
*.DOCX diff=astextplain
16+
*.dot diff=astextplain
17+
*.DOT diff=astextplain
18+
*.pdf diff=astextplain
19+
*.PDF diff=astextplain
20+
*.rtf diff=astextplain
21+
*.RTF diff=astextplain
22+
*.md text diff=markdown
23+
*.mdx text diff=markdown
24+
*.tex text diff=tex
25+
*.adoc text
26+
*.textile text
27+
*.mustache text
28+
*.csv text eol=crlf
29+
*.tab text
30+
*.tsv text
31+
*.txt text
32+
*.sql text
33+
*.epub diff=astextplain
34+
35+
# Graphics
36+
*.png binary
37+
*.jpg binary
38+
*.jpeg binary
39+
*.gif binary
40+
*.tif binary
41+
*.tiff binary
42+
*.ico binary
43+
# SVG treated as text by default.
44+
*.svg text
45+
# If you want to treat it as binary,
46+
# use the following line instead.
47+
# *.svg binary
48+
*.eps binary
49+
50+
# Scripts
51+
*.bash text eol=lf
52+
*.fish text eol=lf
53+
*.sh text eol=lf
54+
*.zsh text eol=lf
55+
# These are explicitly windows files and should use crlf
56+
*.bat text eol=crlf
57+
*.cmd text eol=crlf
58+
*.ps1 text eol=crlf
59+
60+
# Serialisation
61+
*.json text
62+
*.toml text
63+
*.xml text
64+
*.yaml text
65+
*.yml text
66+
67+
# Archives
68+
*.7z binary
69+
*.gz binary
70+
*.tar binary
71+
*.tgz binary
72+
*.zip binary
73+
74+
# Text files where line endings should be preserved
75+
*.patch -text
76+
77+
#
78+
# /////////Exclude files from exporting////////
79+
# You can tell Git not to export certain files or directories when generating an archive.
80+
# If there is a subdirectory or file that you don’t want to include in your archive file but that,
81+
# you do want checked into your project, you can determine those files via the export-ignore attribute.
82+
83+
# .gitattributes export-ignore
84+
# .gitignore export-ignore
85+
# .gitkeep export-ignore

content/arcade blog/arcade GDD.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
+++
22
title = 'Arcade GDD'
33
date = 2024-04-25T17:04:30+01:00
4-
draft = false
4+
draft = true
55
+++
Loading

content/projects/Demise/index.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
+++
2+
title = 'Demise'
3+
date = 2022-12-01
4+
draft = false
5+
+++
6+
7+
![Image](spaceship.png)
8+
> ^ All the cars in this photo are using AI to navigate the city and do their own tasks.
9+
10+
11+
12+
# About the Project
13+
14+
![Image](shot-missile.png)
15+
> ^ The player is shooting another player with a homing missile. The missile is the little yellow dot on the screen between the two spaceships.
16+
17+
I made this game solo around Christmas of *2022* during my 2nd year of university. It’s 3D spaceship PvP demo that works on LAN.
18+
19+
All the net-code and AI is made in Blueprints.
20+
21+
22+
23+
# The Inner Workings of Demise
24+
25+
I made the spaceship shoot missiles that chase the nearest target. The target can be spaceships, other missiles, or green trucks.
26+
27+
I wanted missiles to only see what’s in front of them, to do this I used the *AIPerception* component and custom Blueprint (BP) code to get the nearest target in vision.
28+
29+
![Image](missile-code-snippet.png)
30+
> ^ This is the code that controls the AI perception (targeting system) on the missile.
31+
32+
For the city I populated it with cars that have different AI.
33+
34+
All cars have a wondering mechanic to drive to random locations. The police car and green van variants expand this logic.
35+
36+
- Police cars will randomly chase and stop other cars or vans.
37+
- Green vans will stop at certain towers to put ammo back on the map so a spaceship can get more ammunition.
38+
39+
![Image](bt-blueprint-of-ammo-truck.png)
40+
> ^ Behavior tree of the green van (ammo truck) that controls its AI.
Loading
2.08 MB
Loading

content/projects/Demise/spaceship.png

2.93 MB
Loading

content/projects/LANSpace.md

Lines changed: 0 additions & 6 deletions
This file was deleted.

content/projects/LANSpace/a.png

147 KB
Loading

content/projects/LANSpace/index.md

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
+++
2+
title = 'LANSpace'
3+
date = 2021-08-28
4+
draft = false
5+
+++
6+
7+
![Image](a.png)
8+
> ^ Picture showing 2 games running in the same PC on LAN.
9+
10+
[Repository](https://github.com/codercommand/LANSpace)
11+
12+
In *2021 Falmouth University* advised all programming students to make a 2D game using Python and Pygame before starting their course in September.
13+
14+
I decided to make mine a multiplayer spaceship game, and use a unique way of communicating I had theorised. The purpose of this was to experiment with a different communication method to make a game that doesn’t need a server or a host to work.
15+
16+
The end result was anyone can join or leave the local area network (LAN) at any time without negatively interrupting the experience of other players. The player limit for the LAN is 255 players technically, but in practice it only works with about 20 players on LAN before the LAN begins to suffer networking issues.
17+
18+
While this style of network design has drawbacks, I’m pleased that the experiment was successful.
19+
20+
21+
22+
# The Inner Workings of LANSpace
23+
24+
To network the game I use the UDP Broadcast protocol. Every client listens to port 8080 for other clients already on the network. After learning who is on the network, the client will assign itself a unique number and begin broadcasting its world position and other data on port 8080.
25+
26+
All the clients listen for broadcasts and render the players who are broadcasting.
27+
28+
A death in the game is simulated by not broadcasting the player position. If a client doesn’t receive an update to the location of a player within 0.03 seconds, then the player is removed from their game. Respawning is as simple as broadcasting the player position again.
29+
30+
```python
31+
# A generator used for reading the game network before each game loop.
32+
def network_reader(main_player_id: int) -> list:
33+
...
34+
...
35+
...
36+
# Removes enemies that have stopped playing for more than 1 second.
37+
for x in range(len(game_state)-1, -1, -1):
38+
39+
# Remoevs enemy players that have quit playing.
40+
if game_state[x].type == Type.Actor:
41+
if (time.time() - game_state[x].last_update) > 0.03:
42+
game_state.pop(x)
43+
continue
44+
```
45+
> ^ Code that controls which players are rendered to the screen.
46+
47+
I also made functions to serialized and deserialized player data (like position) from and to bytes. I did this to reduce packet size and because it was fun. There was also a performance concern. I believed it to be faster to have custom serialization code built to purpose instead of processing text or JSON.
48+
49+
```python
50+
# Base type used to make the two seperate player types: Avatar & Player.
51+
class Actor:
52+
def __init__(self, id: int, _type: Type, rotation: int, x: int, y: int, shiptype: int) -> None:
53+
self.type = _type
54+
self.id = id
55+
self.rotation = rotation # I only want to store 0-360 in rotation, nothing other.
56+
self.x = x
57+
self.y = y
58+
self.shiptype = shiptype # Ship type must be between and including 1-4
59+
60+
self.spaceship_cache = None
61+
self.size = 42
62+
63+
def to_bytes(self) -> bytes:
64+
data = []
65+
66+
data.append(self.type)
67+
data.append(self.id)
68+
for x in self.rotation.to_bytes(length=2, byteorder="big", signed=False):
69+
data.append(x)
70+
for x in int(self.x).to_bytes(length=4, byteorder="big", signed=False):
71+
data.append(x)
72+
for x in int(self.y).to_bytes(length=4, byteorder="big", signed=False):
73+
data.append(x)
74+
data.append(self.shiptype)
75+
76+
return bytes(data)
77+
78+
def from_bytes(self, data: bytes) -> None:
79+
self.type = data[0]
80+
self.id = data[1]
81+
self.rotation = int.from_bytes(data[2:4], byteorder="big", signed=False)
82+
self.x = int.from_bytes(data[4:8], byteorder="big", signed=False)
83+
self.y = int.from_bytes(data[8:12], byteorder="big", signed=False)
84+
self.shiptype = data[12]
85+
```
86+
> ^ Code showing the custom serialisation and deserialisation functions I made for the player.
87+
88+
89+
90+
# Flaws with LANSpace
91+
92+
It’s really easy to cheat because there is no authority for the network state, everyone is responsible for their individual character state. For example, to make your player immortal you would continue to broadcast you ships position, this would make you immune to damage because on everyone else's screens you would never die. The game is intended to be played on LAN though so it’s not a big concern. You would be playing with friends or people you know so if you’re cheating it’s because you and your friends want to.
93+
94+
The other problem is that because the game is broadcasting to everyone on the network it has the potential to use up all the bandwidth available for every device. This causes the internet to become slow, similar to a denial of service attack. On testing: 20 players is fine, you can get away with 50, anything higher and the network can’t handle it. The internet will stop working properly with anything over ~80 for everyone connected, including people not playing the game.

content/projects/Sentinel.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

content/projects/Sentinel/banner.png

211 KB
Loading

content/projects/Sentinel/died.png

273 KB
Loading

content/projects/Sentinel/index.md

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
+++
2+
title = 'Sentinel'
3+
date = 2022-01-31
4+
draft = false
5+
+++
6+
7+
![Image](striking-enemy.png)
8+
9+
10+
11+
# About the Project
12+
13+
While doing my 1st year of university in 2022, I participated in a game jam on [itch.io](http://itch.io). It was a 72 hour jam with a theme of ***protect***.
14+
15+
I made the game solo in Godot and used GDScript. This is the 3rd project I’ve ever made in Godot. All the assets for the project are from [itch.io](http://itch.io).
16+
17+
The game loop is simple, kill skeletons till you die then repeat and try to beat your last high score. Current record is by someone else who played the game. Their record is 1483.
18+
19+
![Image](play-menu.png)
20+
> ^ Picture of the main menu.
21+
22+
![Image](banner.png)
23+
> ^ Picture of player killing a skeleton. There is also a dead skeleton on the ground.
24+
25+
![Image](died.png)
26+
> ^ Picture of dead player.
27+
28+
29+
30+
# Code Snippets
31+
32+
This is some ***GDScript*** code snippets from the player script.
33+
34+
```cpp
35+
func _process(delta):
36+
if not died:
37+
input_controller()
38+
attack_enemy_controller()
39+
animation_controller()
40+
physics_controller(delta)
41+
42+
velocity = move_and_slide(velocity, Vector2.UP)
43+
44+
levelup()
45+
```
46+
> ^ The *update* function. Logic for the player uses a state machine separated between multiple functions. These functions are all called from the player *update* function.
47+
48+
```cpp
49+
func animation_controller():
50+
"""
51+
animation_controller is an animation statemachine.
52+
It controls which animations should be playing based on player input.
53+
"""
54+
55+
if not animation_locked and not died:
56+
if dead:
57+
$AnimatedSprite.animation = "death"
58+
animation_locked = true
59+
died = true
60+
$RunAudio.stop()
61+
62+
$DeathTimer.start()
63+
64+
elif not is_on_floor() and $AnimatedSprite.animation == "jump":
65+
$AnimatedSprite.animation = "jumpTransition"
66+
animation_locked = true
67+
68+
elif not is_on_floor():
69+
$AnimatedSprite.animation = "fall"
70+
$RunAudio.stop()
71+
72+
elif jumping and is_on_floor():
73+
$AnimatedSprite.animation = "jump"
74+
animation_locked = true
75+
$RunAudio.stop()
76+
77+
elif attacking:
78+
$AnimatedSprite.animation = get_attack_animation()
79+
animation_locked = true
80+
$AttackAudio.play()
81+
$RunAudio.stop()
82+
83+
elif running:
84+
$AnimatedSprite.animation = "run"
85+
if not $RunAudio.playing:
86+
$RunAudio.play()
87+
88+
else:
89+
$AnimatedSprite.animation = "idle"
90+
$RunAudio.stop()
91+
```
92+
> ^ This is the function responsible for handling the player animations. The logic is all state based, and is called in the code snippet above that shows the player *update* function.
107 KB
Loading
52.9 KB
Loading

content/projects/Swamp Fell.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
+++
22
title = 'Swamp Fell'
3-
date = 2024-04-25T17:06:38+01:00
3+
date = 2024-05-01
44
draft = false
55
+++

0 commit comments

Comments
 (0)