+
|
... |
動作をしたら割り込みを起こす感じのやつについて
+
|
... |
スクリプトを作る場合プレイヤーが何か行動を起こしたときに何かが起こるようなものを作りたい場合がほとんどだと思う
ゲームの方にもともと「プレイヤーが○○をしたときに呼び出される関数」ってのが用意されてるからそれを使うといい感じにできる
例えば
def on_spawn(self,pos):
ってのはスポーンした瞬間にスポーン位置posって情報が入力されて呼び出される関数
def on_spawn(self,pos):
動作1
return connection.on_spawn(self,pos)
ってやるとスポーンしたら動作1が行われる
例として、緑チームのときだけなんかチャットが出る文を作った
def on_spawn(self,pos):
if self.team == self.protocol.green_team:
self.send_chat("you spawned in green team")
return connection.on_spawn(self,pos)
他には
def on_animation_update(self,jump,crouch,sneak,sprint):
はジャンプ、しゃがむ(またはしゃがみ解除)、V(またはV離す)、ダッシュ(またはダッシュ解除)の状態変化が起こった瞬間に呼び出される
def on_animation_update(self,jump,crouch,sneak,sprint):
if self.team == self.protocol.blue_team:
if jump:
self.send_chat("space osita")
elif sprint:
self.send_chat("shift osita")
elif sneak:
self.send_chat("V osita")
elif crouch:
self.send_chat("ctrl osita")
else:
self.send_chat("Shift ka V ka Ctrl wo hanasita")
return connection.on_animation_update(self,jump,crouch,sneak,sprint)
この例だと青チームの人が上記動作を行うとそれに応じたメッセージが表示される
他にもいろいろ
def on_hack_attempt(self, reason):
def on_position_update(self):
def on_weapon_set(self, value):
def on_fall(self, damage):
def on_orientation_update(self, x, y, z):
def on_shoot_set(self, fire):
def on_secondary_fire_set(self, secondary):
def on_walk_update(self, up, down, left, right):
など用意されている(ここに書いたのはごく一部)
戻り値を与えないとバグったり、エラー吐かないのに他のスクリプトが正常に動かなくなったりすることがあるので注意
基本的には
def xxxxxx(self, aaaa, bbbb):
っていう関数には
return connection.xxxxxx(self, aaaa, bbbb)
と戻り値を与えておけばよい
|
AoS世界の座標について
+
|
... |
AoS世界のマップは高さ64,縦横512ブロックの箱庭であるのは常識である。
マップの左右方向がx軸、上下方向がy軸、そして天地方向がz軸である
マップ左上の上空が原点となり、マップ右がx軸正方向、マップ下がy軸正方向、マップの地面方向がz軸正方向となる。
また、z=62は一番下の掘れない地面で、z=63は水面ブロックである。
512*512*64の領域はブロックを置けたりグレネードが爆発できたりする領域の話で、プレイヤーが存在できる世界はこれだけではない。
z>63の、海よりも深い領域も存在する。スクリプトを使うと掘れたりする。なんか真っ黒で、プレイヤーも真っ黒になった。
しかしその領域に足を踏み入れるとバグって鯖が落ちるので注意。
z<0のzがマイナスになるゾーンも存在する。この領域では問題なくプレイヤーが動くことができる。
しかし、z<0領域ではグレネードにダメージが乗らないほか、ブロックを置くことができない。
また、あまり高く行き過ぎる(z<-80くらい)とクライアントが落ちる事があるので注意。
マップ左右(0<x<511)からはみ出した領域では、コマンドなどは打てるが移動ができなくなる。
マップ上下(0<y<511)からはみ出すとクライアントが落ちる。
AoS世界の座標まとめ
通常世界は
0<x<511
0<y<511
0<z<63
の領域。
x軸は右が正
y軸は下が正
z軸は地面が正
|
現在位置取得するやつについて
+
|
... |
x, y, z = self.world_object.position.get()
この一行で変数x,y,zにselfで指定されるプレイヤーの座標が代入される。
pos = self.world_object.position
でも同様にpという変数に座標が代入されるが、この座標はvertex3型である(俺もよくわからん)
つまるところ pos = vertex3(x,y,z) である
もちろん変数名は適当なものでおkである
なお、この座標はプレイヤーの頭の位置であるので、足元の座標だとx,y,z-2くらいになる
|
現在方向取得するやつについて
+
|
... |
プレイヤーの向いてる方向を取得する
方向は半径1の球の表面の点の座標で表されることが多い
例えば真上を向くときは(0,0,-1)であるし、マップ右側を向くときは(0,0,1)、マップ左下正面を向くならば(-0.7,0.7,0)くらいである。
x2,y2,z2 = self.world_object.orientation.get()
座標の取得と同様にこの一行でおk
ori = self.world_object.orientation
でもおk
座標と同様に ori = vertex3(x2,y2,z2)
|
グレネード生成するやつについて
+
|
... |
基本的なこととして、AoS世界のグレネードは「ダメージの発生する見えないグレネード」と「目に見えるグラフィックだけのハリボテグレネード」の二種類が存在して、
この二つが重なって同じ向きに同じ速さで投射されることでいつものグレネードが出来上がっている。
self.protocol.world.create_object(Grenade, time, pos, None, ori, self.grenade_exploded)
これが目に見えないダメージのある方のグレネード生成部分
括弧内のGrenadeはさておき、二つ目のtimeが生成から爆発までの時間。より正確にいうと、生成から最後のself.grenade_exprodedという関数を呼び出すまでの時間。
最後の引数の関数を変えれば爆発時に別の関数を呼び出すことも可能
三つ目のposはグレネードの生成点の座標(vertex3型)
四つ目のNoneはよくわからん(誰か教えて)
↑この部分にposやoriと同形式のデータを与えるとその分が初速に加算されるらしい まあ気にしなくてよいかと
五つ目のoriはグレネードの初速
というわけで、この関数ひとつで、目に見えないtime秒後に爆発するグレネードがposからoriに向けて発射される。
例えば
self.protocol.world.create_object(Grenade, 2.0, Vertex3(255,255,32), None, Vertex3(0,0,-2), self.grenade_exploded)
とやると、座標(255,255,32)の点から(0,0,-1)(真上向き)に結構な速度でグレネードが発射され、2秒後に爆発される。
だがこれだけだと目に見えない。
目に見えるハリボテグレネードの生成はコチラ
grenade_packet.value = time
grenade_packet.player_id = self.player_id
grenade_packet.position = pos.get()
grenade_packet.velocity = (a,b,c)
self.protocol.send_contained(grenade_packet)
1行目は爆発までの時間
2行目は誰のグレネードかを書く
3行目は生成座標。vertex3ではなく普通の座標。
4行目は初速。こちらも普通の座標
5行目はよくわからんけどこのまま突っ込んどきゃいいと思う
というわけでこれらを合わせると、目に見えて爆発グラフィックも出るしダメージも喰らうグレネードができる。
例として3秒で爆発するグレネードをプレイヤーの頭の2ブロック前から向いてる向きに、すごい速さですっ飛ばすスクリプト部分はこんな感じ
SPEED=5
x, y, z = self.world_object.position.get()
p = Vertex3(x+a*2,y+b*2,z+c*2)
a,b,c = self.world_object.orientation.get()
a = a * SPEED
b = b * SPEED
c = c * SPEED
self.protocol.world.create_object(Grenade, 3.0, p, None, vertex3(a,b,c), self.grenade_exploded)
grenade_packet.value = 3.0
grenade_packet.player_id = self.player_id
grenade_packet.position = p.get()
grenade_packet.velocity = (a,b,c)
self.protocol.send_contained(grenade_packet)
グレネードの着発信管の作り方
グレネードを時間じゃなくて、砲弾みたいにブロックと衝突した瞬間に爆発するようにしたいことは多いはず
そのやり方がこれ
grenade = self.protocol.world.create_object(Grenade, 0.0, pos, None, ori, None)
collision = grenade.get_next_collision(UPDATE_FREQUENCY)
if collision:
impact, x, y, z = collision
弾道計算用仮想グレネードを生成して、弾道を計算させるというもの。
一行目で弾道計算用のダミーグレネード「grenade」を生成(posから、初速oriで投射爆発は起こらない)というもの
二行目でダミーグレネードの弾道上でブロックへの衝突が生じる地点の座標、衝突までの時間を計算
collosionの中身はimpact=衝突までの時間、x,y,z=衝突座標の二点
重要なのは時間。
衝突までの時間がわかったので、それを実際に発射するグレネードの爆発時間にすれば、ちょうど衝突の瞬間に爆発が起こる。
例として、右クリでスコープ除いてるときにVを押すと向いてる向きに着発グレネードが飛んでゆくスクリプト全文を示す。
from pyspades.constants import *
from pyspades.world import Grenade
from pyspades.server import grenade_packet
from pyspades.common import Vertex3
from pyspades.constants import UPDATE_FREQUENCY
SPEED = 1.5
def apply_script(protocol,connection,config):
class GrenadeConnection(connection):
def on_animation_update(self,jump,crouch,sneak,sprint):
if sneak and self.world_object.secondary_fire:
x, y, z = self.world_object.position.get()
pos = Vertex3(x, y, z+1)
a,b,c = self.world_object.orientation.get()
a = a * SPEED
b = b * SPEED
c = c * SPEED
forward = Vertex3(a, b, c)
grenade = self.protocol.world.create_object(Grenade, 0.0, pos, None, forward, None)
collision = grenade.get_next_collision(UPDATE_FREQUENCY)
if collision:
impact, x, y, z = collision
self.protocol.world.create_object(Grenade, impact, pos, None, forward, self.grenade_exploded)
grenade_packet.value = impact
grenade_packet.player_id = self.player_id
grenade_packet.position = pos.get()
grenade_packet.velocity = (a,b,c)
self.protocol.send_contained(grenade_packet)
return connection.on_animation_update(self,jump,crouch,sneak,sprint)
return protocol,GrenadeConnection
あと、これ見てわかるようにグレネード生成のときにはVertex3とかgrenade_packetとかいろいろインポートしなきゃならんので注意
|
何秒後に動作を起こす系
+
|
... |
callLater(時間, self.関数, 呼び出す関数の引数)
例
def _on_reload(self):
if self.weapon == 0 or self.weapon == 1:
callLater(0.01, self.reload_after)
----略---
self.send_contained(weapon_reload)
return connection._on_reload(self)
これだとリロード時に武器が0または1(rifleまたはSMG)の時、リロードの0.01秒後に引数なしのreload_afterを実行
例
def flight(self, x, y, z):
if self.flying:
x2, y2, z2 = self.world_object.orientation.get()
x += x2
y += y2
z += z2
self.set_location((x, y, z))
callLater(0.04, self.flight, x, y, z)
これは
座標(x,y,z)を引数としてflight関数が読み込まれたとき
flying が True であれば
向いてる方向をゲットして、それぞれ三軸x2,y2,z2(-1から1まで)として
各座標を方向の分だけずらして
プレイヤーを新たなx,y,zにワープさせて
0.04秒後に flight関数を x,y,zを引数として呼び起こす
以下ループ
という意味
使うにはreactorのimportが必要
from twisted.internet.reactor import callLater
|
メッセージを表示する関数の使い方
+
|
... |
self.send_chat('message no naiyou')
が基本
変数を突っ込む場合はメッセージに%sを入れて、引用符閉じた後に% 変数名 を入れる
self.send_chat('You have %s medkit!' % self.medkits)
→チャットの内容「You have 3 medkit!」
上記のだと赤い文字で個人にだけ送られるタイプのチャットになる。
青い文字で鯖からのメッセージとして表示する場合はselfとsend_chatの間にprotocolを入れて
self.protocol.send_chat("----")
とすればおk
|
selfとは、connectionとはなんぞや
+
|
... |
スクリプト眺めてるとめっちゃ出てくるこいつらは、変数や関数にくっついて「誰の」という部分を表す。
例えばこの例では(connection)が引数で出てる
コマンド打ってこの関数を呼び出した奴がconnectionになる。
だからconnection.medkits は「コマンド打ったプレイヤー」のmedkitsを表す変数になるし、connection.set_hp()はそいつのHPを変化させる関数になる
def medkit(connection):
if connection.medkits and connection.hp < 100:
connection.set_hp(connection.hp + connection.protocol.heal_amount,type = FALL_KILL)
connection.medkits -= 1
connection.send_chat('You have been healed')
else:
connection.send_chat("You don't have any medkits or have full health!")
こっちの例ではスポーンしたときに自動で呼び出される関数なのでselfになってる
つまりこの場合、self=スポーンしたプレイヤーとなる。
def on_spawn(self, pos):
self.medkits = default_medkits
self.send_chat('You have %s medkit!' % self.medkits)
return connection.on_spawn(self, pos)
self.medkits = default_medkitsではスポーンしたひとのmedkit所持数にdefault_medkitsを代入している。
self.send_chat()ではselfの人にメッセージを送っている。
引数がconnectionの関数にselfをつけるとエラー吐くし、逆もだめなので引数を見て適当な方をつけましょう。
例えばあるプレイヤー"player"が味方か敵かを判定する場合
if player.team == connection.team:
とやるか、
if player.team == self.team:
とやるかを判断する場合は、そのdef____()のなかにselfがあるかconnectionがあるかを見て、それをつければいいのである。
|
|