Introduction
Pressing Competition 2 or Typing Competition 2 is a Godot game which allows you to choose characters and fight against each other.
It’s open-sourced under MIT here
You can find the showcase here
It’s developed with Godot Mono 3.2.3
Steps
Preparation
What you need:
- Godot Mono 3.2.3 or later
- Source code from Github
In the tutorial, you want to get ZJS from Hell Hole Studios into the game.
0. Note
This tutorial is updated on 2021/1/30 and is aimed for version 1.5
This tutorial is updated again on 2021/3/6 to match 1.10
This tutorial is updated agin on 2021/3/13 to match 1.11
1. Import
Download source code and import it as Godot project. You are done!
Due to some Godot bugs, please ignore all errors.
2. Adding a Character Group
Create a new folder under res://script/characters/Groups
called HHS
and add a new script extending CharGroup
:
1 | extends CharGroup |
Provide two parameters to super._init()
:
name
:String, the name of the groupchars
:Array, theCharacterBase
s in this group
Register your group at res://script/characters/AvailableCharacters.gd
:
1 | extends Node |
3. Adding a character
Create file res://script/characters/Groups/HHS/ZJS.gd
extending CharacterBase
:
Let’s say ZJS’s skill is to deal 1000 damage to himself
1 | extends CharacterBase |
3.1 The init function
Define the following properties here:
maxhp
:Int(1-1000)atk
:Int(1-5)name
:StringskillCost
:Int(1-2000). Don’t set it to 0 unless it’s a passive skill.image
:String Image pathheal
:Int(1-5)desc
:String DescriptionskillType
:Int(0-1). Optional. Set this to 1 to set the skill to be a passive type.version
:Int(0-1). Optional. Set this to 1 for a more advanced skill overwrite. 1 is recommended for >=1.10 usersnosub
:Bool Optional. Setting this to true will make the character unavailable for minions
3.2 The onSkillA function
onSkillA
function comes with 6 parameters. It’s called when player uses a skill. It’s also called every frame if it’s a passive skill. This method won’t be called unless version
is set to 1.
me
: Character the skill user side’s mastersub
: Character the skill user side’s minionenemy
: Character the skill enemy side’s masterenemySub
: Character the skill enemy side’s minionscene
: GameSubview current sceneisSub
: Bool whether the skill was called by a minion
3.3 The onSkill function
onSkill
is an easier version of onSkillA
. This method won’t be called unless version
is set to 0(default).
me
:Character the skill userenemy
:Character skill user’s enemyscene
:GameSubview current GameSubview scene
3.4 Character Properties
Let’s take a look at what’s in the class Character
so you know what you can do:
1 | # Character.gd |
CharacterBase uses Singleton design principle so:
base
is read-only. Writing it will cause the next round to be corrupted. Write to corresponding variables instead
Do not use self
or internal variables in onSkill. Writing it will cause the next round to be corrupted. Write to me
or me.vars
instead
Use scene.emit_signal("damage_given",...,...)
to deal damage or the HP will not be displayed correctly
Some common scenario
- Increase attack by 1:
me.atk+=1
- Double skill cost:
enemy.skillCost*=2
- Adding Status:
enemy.status.append(GDBuff.new("test",600,1,2))
- Deal 60 damage:
scene.emit_signal("damage_given",enemy,60)
- Heal 60 HP:
scene.emit_signal("damage_given",me,-60)
- Writing to user variable:
me.vars["123"]+=1
- Writing to scene objects: Lorelei:6
- Initalizing a variable fast: Koishi:6
- Checking minion: Satono:6
- Calling others’ skill: Rin:8
3.5 Key controls(>=1.5)
- Use
Character.checkAction("attack/defense/skill/gauge")
to check if a character is attacking/healing/gauge-filling/using skill at the same frame this is called. Character.key
holds the bitmask for the actions at this frame- Use
Character.checkA1("attack/defense/skill/gauge")
to check if a key is just pressed - Use
Character.checkA2("attack/defense/skill/gauge")
to check if a key is pressed/hold - Use
Character.checkB1("attack/defense/skill/gauge",default)
to check if a key is just pressed or return default if it’s AI - Use
Character.checkB2("attack/defense/skill/gauge",default)
to check if a key is pressed/hold or return default if it’s AI
3.6 Adding pictures
The last step is to put your picture in the path you set to. Make sure it’s facing right. It’s recommended to put it under res://pic
4. Status
Use status to create lengthy events!
4.1 Built-in Status
System comes with built-in status:
GDBuff.new(name,duration,damage,interval)
will inflict a status calledname
and isduration
frames long. It will causedamage
damage everyinterval
framesGSBuff.new(name,duration,damage,interval)
will inflict a status calledname
and isduration
frames long. It will losedamage
skill gauge everyinterval
framesGDRBuff.new(name,duration,da,db,interval)
will inflict a status calledname
and isduration
frames long. It will causeda
todb
damage randomly everyinterval
frames
4.2 Custom Status
Custom Status should extends Status
:
1 | extends Status |
This is another example:
1 | extends Status |
Note that using self and internal variables are okay:
1 | extends Status |
5. Global & Config
scene.Global
contains the Global variables, use them if you need:
1 | # Global.gd |
6. Minions (>=1.10)
Minions are a new concept and game mechanics in 1.10. The minion is stored in Global.s1
and Global.s2
as a character. It’s basically a character with their HP,heal,atk unused, so don’t deal damage or cast status on them. You can set nosub
to true to prevent a character being selected as minion.
The minion gauge is stored in minion’s skillGauge
variable and the threshold is in skillCost
.
When master attacks, gauge will increase by 10. When master gets hurt, gauge will increase by damage
.
7. Refer to source code for 100+ examples!
8. Build and release!
Appendix
You should release your own version of PC2 with credits and link to the original version. You can also have your characters included in the main version with a pull request.
So, with that being said, enjoy modding and creating!